primer C++笔记
文本查询再探
将层次关系隐藏于接口类中
#include "TextQuery.h"
#include <stdlib.h>
//这是一个抽象基类,具体的查询类型从中派生,所有成员都是private的
class Query_base
{
friend class Query;
protected:
//用于eval函数
using line_no = TextQuery::line_no;
virtual ~Query_base() = default;
private:
//eval返回与当前Query匹配的QueryResult
virtual QueryResult eval(const TextQuery&) const = 0;
//rep是表示查询的一个string
virtual string rep() const = 0;
};
//这是一个管理Query_base继承体系的接口类
class Query
{
//这些运算符需要接受shared_ptr的构造函数,而该函数是私有的
friend Query operator~(const Query&);
friend Query operator&(const Query&, const Query&);
friend Query operator|(const Query&, const Query&);
public:
//构建一个新的WordQuery
Query(const string&);
//接口函数:调用对应的Query_base操作
QueryResult eval(const TextQuery& t) const
{
return q->eval(t);
}
string rep() const
{
return q->rep();
}
private:
Query(shared_ptr<Query_base> query) :q(query) {}
shared_ptr<Query_base> q;
};
//Query的输出运算符
ostream& operator<<(ostream&os, const Query& query)
{
//Query::rep通过它的Query_base指针对rep()进行了虚调用
return os << query.rep();
}
class WordQuery : public Query_base
{
//Query使用WordQuery构造函数
friend class Query;
WordQuery(const string& s) : query_word(s) {}
//具体的类:WordQuery将定义所有继承而来的纯虚函数
QueryResult eval(const TextQuery &t) const
{
return t.query(query_word);
}
string rep() const
{
return query_word;
}
private:
string query_word;
};
//接受string的WordQuery构造函数
inline Query::Query(const string& s) : q(new WordQuery(s)) {}
class NotQuery : public Query_base
{
friend Query operator~(const Query&);
NotQuery(const Query &q) : query(q) {}
//具体的类:NotQuery将定义所有继承而来的纯虚函数
QueryResult eval(const TextQuery&) const;
string rep() const
{
return "~(" + query.rep() + ")";
}
Query query;
};
inline Query operator~(const Query&operand)
{
return shared_ptr<Query_base>(new NotQuery(operand) );
}
//抽象基类,保存两个运算对象的查询类型所需的数据
class BinaryQuery : public Query_base
{
protected:
BinaryQuery(const Query &l, const Query &r, string s)
:lhs(l), rhs(r), opSym(s) {}
//抽象类:BinaryQuery不定义eval
string rep() const
{
return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
}
Query lhs, rhs;
string opSym;
};
class AndQuery : public BinaryQuery
{
friend Query operator&(const Query&, const Query&);
AndQuery(const Query& left, const Query& right)
:BinaryQuery(left, right, "&") {}
//具体的类:AndQuery继承了rep并且定义了其他纯虚函数
QueryResult eval(const TextQuery&) const;
};
inline Query operator&(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
class OrQuery : public BinaryQuery
{
friend Query operator|(const Query&, const Query&);
OrQuery(const Query& left, const Query& right)
:BinaryQuery(left, right, "&") {}
//具体的类:AndQuery继承了rep并且定义了其他纯虚函数
QueryResult eval(const TextQuery&) const;
};
inline Query operator|(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
//返回运算对象查询结果set的并集
QueryResult AndQuery::eval(const TextQuery& text) const
{
auto right = rhs.eval(text), left = lhs.eval(text);
auto ret_lines = make_shared<set<line_no>>(left.begin(), left.end());
ret_lines->insert(right.begin(), right.end());
return QueryResult(rep(), ret_lines, left.get_file());
}
//返回运算对象查询结果set的交集
QueryResult OrQuery::eval(const TextQuery& text) const
{
auto right = rhs.eval(text), left = lhs.eval(text);
auto ret_lines = make_shared<set<line_no>>();
set_intersection(left.begin(), left.end(), right.begin(), right.end(),inserter(*ret_lines, ret_lines->begin()));
return QueryResult(rep(), ret_lines, left.get_file());
}
//返回运算对象的结果set不存在的文本行
QueryResult NotQuery::eval(const TextQuery& text) const
{
auto result = query.eval(text);
auto ret_lines = make_shared<set<line_no>>();
auto beg = result.begin(), end = result.end();
auto sz = result.get_file()->size();
for (size_t n = 0; n != sz; ++n)
{
if (*beg != n || beg == end)
ret_lines->insert(n);
else if (beg != end)
++beg;
}
return QueryResult(rep(), ret_lines, result.get_file());
}
int main(int argc, char** argv)
{
system("pause");
return 0;
}
TextQuery.h
#pragma once
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <set>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
//保存查询结果
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
using line_no = vector<string>::size_type;
QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f)
:sought(s), lines(p), file(f) {}
set<line_no>::iterator begin()
{
return lines->begin();
}
set<line_no>::iterator end()
{
return lines->end();
}
shared_ptr<vector<string>>& get_file()
{
return file;
}
private:
string sought;
shared_ptr<set<line_no>> lines;
shared_ptr<vector<string>> file;
};
ostream& print(ostream& os, const QueryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " times" << endl;
for (auto num : *qr.lines)
{
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
}
return os;
}
//文本查询类
class TextQuery
{
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream &);
QueryResult query(const string& sought) const;
private:
shared_ptr<vector<string>> file;
map<string, shared_ptr<set<line_no>>> wm;
};
TextQuery::TextQuery(ifstream & is)
:file(new vector<string>)
{
string text;
while (getline(is, text))
{
file->push_back(text);
int n = file->size() - 1;
istringstream line(text);
string word;
while (line >> word)
{
auto &lines = wm[word];
if (!lines)
lines.reset(new set<line_no>);
lines->insert(n);
}
}
}
QueryResult TextQuery::query(const string& sought) const
{
//如果未找到sought,我们将返回一个指向此set的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if (loc == wm.end())
return QueryResult(sought, nodata, file);
else
return QueryResult(sought, loc->second, file);
}
void runQueried(ifstream &infile)
{
//保存文件并建立查询map
TextQuery tq(infile);
while (true)
{
cout << "enter word to look for, or q to quit: ";
string s;
if (!(cin >> s) || s == "q")
break;
//指向查询并打印结果
print(cout, tq.query(s)) << endl;
}
}