没搞明白。
题目来源:C++ Primer 15.41题目。
查询满足诸如 ~a&b|c条件的文本。
Query.h
#ifndef QUERY_H
#define QUERY_H
#include "TextQuery.h"
#include <string>
#include <set>
#include <iostream>
#include <fstream>
using namespace std;
///用作具体查询类型的基类抽象类
class Query_base{
friend class Query;
protected:
typedef TextQuery::line_no line_no;
virtual ~Query_base(){}
private:
//
virtual set<line_no>
eval(const TextQuery &)const =0;
virtual ostream&
display(ostream& =cout) const =0;
};
///Query句柄类
class Query {
//这些操作符需要访问 Query_base*的构造函数
friend Query operator ~(const Query &);
friend Query operator |(const Query &,const Query &);
friend Query operator &(const Query &,const Query &);
public:
Query(const string&);//建立新的WordQuery对象
//管理指针及使用计数的复制控制成员
Query(const Query & c):q(c.q),use(c.use){++*use;}
~Query(){decr_use();}
Query& operator=(const Query &);
//接口函数:将调用相应的Query_base 操作
set<TextQuery::line_no>
eval(const TextQuery &t)const{
return q->eval(t);
}
ostream &
display(ostream &os)const {
return q->display(os);
}
private:
Query(Query_base* query):q(query),use(new size_t(1)){}
Query_base *q;
size_t *use;
void decr_use(){
if(--*use==0){
delete q;
delete use;
}
}
};
inline Query & Query::operator=(const Query &rhs){
++*rhs.use;
decr_use();
q=rhs.q;
use=rhs.use;
return *this;
}
// I/O操作符一般定义为非成员,
//因为类成员的左操作数必为类对象,item<<cout与日常习惯相反
inline ostream& operator<<(ostream &os,const Query &q){
return q.display(os);
}
//WordQuery
class WordQuery: public Query_base{
friend class Query;//Query使用WordQuery的构造函数
WordQuery(const string &s):query_word(s){}
//具体类WordQuery定义所有继承来的纯虚函数
set<line_no> eval(const TextQuery &t)const{
return t.run_query(query_word);
}
ostream& display(ostream& os)const {
return os<<query_word;
}
string query_word;
};
//这个函数需要用到WordQuery的构造函数
inline Query::Query(const string &s):q(new WordQuery(s)),use(new size_t(1) ){}
//NotQuery类
class NotQuery :public Query_base{
friend Query operator ~(const Query &);
NotQuery(Query q):query(q){}
//具体类NotQuery定义所有继承而来的纯虚函数
set<line_no>
eval(const TextQuery &t) const;
ostream& display(ostream& os)const{
return os<<"~("<<query<<")"<<endl;
}
const Query query;
};
//二元抽象类
class BinaryQuery:public Query_base{
protected:
BinaryQuery(Query left,Query right,string op):
lhs(left),rhs(right),oper(op){}
//抽象类BinaryQuery不定义eval(此时仍为抽象类)
ostream& display(ostream &os)const{
return os<<"("<<lhs<<")"<<oper<<"("<<rhs<<")";
}
const Query lhs,rhs;
const string oper;
};
class AndQuery: public BinaryQuery{
friend Query operator&(const Query&,const Query&);
AndQuery(Query left,Query right):
BinaryQuery(left,right,"&"){}
//具体类AndQuery继承display并保持为虚函数
set<line_no> eval(const TextQuery&)const;
};
class OrQuery:public BinaryQuery{
friend Query operator|(const Query&, const Query&);
OrQuery(Query left,Query right):BinaryQuery(left,right,"|"){};
//具体类OrQuery继承display并保持为虚函数
set<line_no> eval(const TextQuery&)const;
};
///
inline Query operator &(const Query &lhs,const Query &rhs){
return new AndQuery(lhs,rhs);
}
inline Query operator |(const Query &lhs,const Query &rhs){
return new OrQuery(lhs,rhs);
}
inline Query operator ~(const Query &rhs){
return new NotQuery(rhs);
}
#endif
Query.cpp
#include "Query.h"
#include "TextQuery.h"
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
//返回不在其操作结果中的行号集合
set<TextQuery::line_no>
NotQuery::eval(const TextQuery &file) const{
//计算其操作数的结果集
set<TextQuery::line_no> has_val=query.eval(file);
set<line_no> ret_lines;
for(TextQuery::line_no n=0;n!=file.size();n++){
if(has_val.find(n)==has_val.end())
ret_lines.insert(n);
}
}
//返回其操作数结果集的交集
set<TextQuery::line_no>
AndQuery::eval(const TextQuery &file)const{
set<TextQuery::line_no> left=lhs.eval(file),right=rhs.eval(file);
set<line_no> ret_lines;//保存运算结果
//将左右操作数结果的交接写至ret_lines
set_intersection(left.begin(),left.end(),right.begin(),right.end(),
inserter(ret_lines,ret_lines.begin()));
return ret_lines;
}
//返回操作数结果集的并集
set<TextQuery::line_no>
OrQuery::eval(const TextQuery &file)const{
set<line_no> right=rhs.eval(file),
ret_lines=rhs.eval(file);
/*
将未在ret_lines中出现的right中的行号插入到ret_lines中,
retu_lines.inset(right.begin(),right.end());所用的编译器不支持
带两个迭代器参数的insert函数,改用如下代码:
*/
for(set<line_no>::const_iterator iter=right.begin();
iter!=right.end();++iter){
ret_lines.insert(*iter);
}
return ret_lines;
}
TextQuery.h
/*使用set容器存储行号*/
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <string>
#include <vector>
#include <set>
#include <map>
#include<cctype>
#include<iostream>
#include <fstream>
#include<cstring>
using namespace std;
class TextQuery{
public:
//类型别名
typedef string::size_type str_size;
typedef vector<string>::size_type line_no;
//接口
//read_file 建立给定文件的内部数据结构
void read_file(ifstream &is){
store_file(is);
build_map();
}
//run_query查询给定单词并返回该单词所在的行的行号集合
set<line_no> run_query(const string&) const;
//text_line返回输入文件中指定行号对应的行
string text_line(line_no) const;
line_no size() const;
private:
//read_file所用的辅助函数
void store_file(ifstream &);//存储输入文件
void build_map();//将每一个单词与一个行号集合相关联
//保存输入文件
vector<string> lines_of_text;
//将单词与出现该单词的行的行号集合相关联
map<string,set<line_no> > word_map;
//去掉标点并将字母变成小写
static string cleanup_str(const string&);
};
#endif
#include "TextQuery.h"
#include <sstream>
string TextQuery::text_line(line_no line)const{
if(line<lines_of_text.size())
return lines_of_text[line];
//throw out_of_range("line number out of range");
}
//读输入文件,将每行存储为lines_of_text的一个元素
void TextQuery::store_file(ifstream &is){
string textline;
while(getline(is,textline))
lines_of_text.push_back(textline);
}
//在输入vector中找以空白为间隔的单词
void TextQuery::build_map(){
//处理输入vector中的每一行
for(line_no line_num=0;line_num!=lines_of_text.size();++line_num){
//一次读一个单词
istringstream line(lines_of_text[line_num]);
string word;
while(line>>word){
//将行号加入到set容器中
//若单词不在map容器中,下标操作将加入该单词
word_map[cleanup_str(word)].insert(line_num);
}
}
}
set<TextQuery::line_no>
TextQuery::run_query(const string& query_word)const{
//注意,为了避免在word_map中加入单词,使用find函数而不用下标操作
map<string,set<line_no> >::const_iterator
loc=word_map.find(query_word);
if(loc==word_map.end())
return set<line_no>();
else
//获取并返回与该单词关联的行号set对象
return loc->second;
}
//去掉标点并将字母变成小写
string TextQuery::cleanup_str(const string &word){
string ret;
for(string::const_iterator it=word.begin();
it!=word.end();++it){
if(!ispunct(*it))
ret+=tolower(*it);
}
return ret;
}
//获取文本行数
vector<string>::size_type TextQuery::size() const{
return lines_of_text.size();
}
main.cpp
/*
使用TextQuery类、Query类及Query_base类层次,
计算和打印如图15-4所示的查询
Query("fiery")&Query("bird")|Query("wind")
*/
#include "Query.h"
#include "TextQuery.h"
string
make_plural(size_t ctr,const string& word,const string& ending){
return (ctr==1)?word:word+ending;
}
ifstream&
open_file(ifstream& in,const string& file){
in.close();//close in case it was already open
in.clear();//clear any existing errors
//if the open fials, the stream will be in an invalid state
in.open(file.c_str());//open the file we were given
return in;//condition state is good if open succeeded
}
void print_results(const set<TextQuery::line_no>& locs,const TextQuery& file){
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size=locs.size();
//如果找到匹配的结果,则输出匹配的行数
cout<<"match occurs "<<size<<" "<<make_plural(size,"time","s")<<endl;
//输出出现该单词的每一行
line_nums::const_iterator it=locs.begin();
for(; it!=locs.end();++it){
cout<<"\t(line"
//行号从1开始
<<(*it)+1<<")"
<<file.text_line(*it)<<endl;
}
}
int main(int argc,char **argv){
//打开要在其中进行查询的文本文件
ifstream infile;
if(!open_file(infile,"a.txt")){
cerr<<"No input file!"<<endl;
return 1;
}
TextQuery file;
file.read_file(infile);//读入文本,建立map容器
typedef set<TextQuery::line_no> line_nums;
//构造查询
Query q=Query("the")&Query("such")|Query("will");
//计算查询,获得匹配行的行号集合
const line_nums& locs=q.eval(file);
//输出查询表达式
cout<<"\nExecuted Query for: "<<q<<endl;
//输出查询结果
print_results(locs,file);
return 0;
}
objects= main.o Query.o TextQuery.o
test:$(objects)
g++ -o test $(objects)
main.o:
Query.o:TextQuery.h
TextQuery.o:
.PHONY :clean
clean:
rm test $(objects)