c++ primer 5ed 15.9文本查询程序再探

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/woyaoxuechengxu/article/details/52134330

头文件:

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include <memory>
#include <algorithm>
#include <initializer_list>
#include <stdexcept>
class StrBlob
{
using line_no = std::vector<std::string>::size_type;
public:
// default constructors
StrBlob() : data(std::make_shared<std::vector<std::string>>()) { }


// size operations
line_no size() const { return data->size(); }


void push_back(const std::string &t) { data->push_back(t); }
std::ostream &PRINT(std::ostream &os,
std::shared_ptr<std::set<line_no>> s) const;
private:
std::shared_ptr<std::vector<std::string>> data;
};




class QueryResult;//必须在TextQuery定义之前声明先声明
class TextQuery
{
public:
TextQuery(std::ifstream&);
using line_no = std::vector<std::string>::size_type;
//类的初始化函数,从一个文件里面读取单词的信息存入
//StrBob和map中
QueryResult query(const std::string &) const;
//用户将想要查询的单词作为参数传入,返回一个被初始化的QueryResult
private:
StrBlob file;
//指向一个元素为string的vector的智能指针
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
//将文本中的单词和出现的行数关联起来
};


class QueryResult
{
friend std::ostream &print(std::ostream &, const QueryResult&);
public:
using line_no = std::vector<std::string>::size_type;
QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p,
StrBlob f) :sought(s),
lines(p), file(f){}
//储存查询信息的函数,接受三个参数,第一个参数表示用户想要查询的单词
//第二个是指向保存单词行数信息的set容器的智能指针,第三个参数是
//StrBob类(其实就是指向保存每一行文本信息的元素
//为string的vector的智能指针)
const StrBlob& get_file() const
{ return file; }
//返回StrBob类的一个引用
std::set<TextQuery::line_no>::iterator begin() 
{ return lines->begin(); }
//返回一个指向set容器首元素的迭代器
std::set<TextQuery::line_no>::iterator end()
{ return lines->end(); }
//返回一个指向set容器最后元素之后位置的迭代器
private:
std::string sought;//用户查询的单词
std::shared_ptr<std::set<line_no>> lines;
StrBlob file;
};


std::ostream &print(std::ostream &os, const QueryResult &qr);


class Query_base//抽象基类
{
friend class Query;
protected:
using line_no = TextQuery::line_no;
virtual ~Query_base() = default;//默认虚析构函数
private:
virtual QueryResult eval(const TextQuery&) const = 0;
virtual std::string rep() const = 0;
};


class WordQuery : public Query_base
{
friend class Query;
WordQuery(const std::string &s) :query_word(s){}
std::string query_word;//要查找的单词
QueryResult eval(const TextQuery &t) const
{
return t.query(query_word);
}
//这个函数很简单,直接将用户输入的单词用来初始化一个WordQuery
//然后调用TextQuery的query函数即可
std::string rep() const{ return query_word; }
//这个函数就是用来返回用户查询的单词
};


class Query
{
friend Query operator~(const Query &);
friend Query operator|(const Query &,const Query &);
friend Query operator&(const Query &,const Query &);
public:
Query(const std::string& s) : q(new WordQuery(s)){}
QueryResult eval(const TextQuery &t) const{ return q->eval(t); }
std::string rep() const{ return q->rep(); }
private:
Query(std::shared_ptr<Query_base> query) :q(query){}
//将会被用于隐式装换
std::shared_ptr<Query_base> q;
};




class NotQuery: public Query_base
{
friend Query operator~(const Query &);
NotQuery(const Query &q) :query(q){}
Query query;
std::string rep() const{ return "~( " + query.rep() + " )"; }
QueryResult eval(const TextQuery &)const;
};
inline Query operator~(const Query &operand)
{
return std::shared_ptr<Query_base>(new NotQuery(operand));
//实际上还隐含了一层转换,将shared_ptr<Query_base>(***)转换为Query
}


class BinaryQuery :public Query_base
{
protected:
BinaryQuery(const Query &l, const Query &r, std::string s)
:lhs(l), rhs(r), opSym(s){}
Query lhs, rhs;//左侧运算对象和右侧运算对象
std::string opSym;//运算符的名字
std::string rep() const {
return "(" + lhs.rep() + ""
+opSym + " " + rhs.rep() + ")";
}
};//继承了eval(),覆盖了rep()函数,也是抽象基类




class AndQuery :public BinaryQuery
{
friend Query operator&(const Query&, const Query&);
AndQuery(const Query &left, const Query &right)
:BinaryQuery(left, right, "&"){}
QueryResult eval(const TextQuery&) const;
};
inline Query operator&(const Query &lhs, const Query &rhs)
{
return std::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, "|"){}
QueryResult eval(const TextQuery&) const;
};
inline Query operator|(const Query &lhs, const Query &rhs)
{
return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}


inline std::ostream& operator<<(std::ostream &os, const Query &query)
{
return os << query.rep();
}


cpp://这部分基本和书本上给的相同,基本都是照搬了

using namespace std;


ostream& StrBlob::PRINT(ostream &os,
shared_ptr<set<vector<string>::size_type>> s) const//自定义的PRINT函数,方便打印最后的结果
{
for (auto num : *s)
{
os << "\t(line " << num + 1 << ") " <<
*(data->begin() + num) << endl;
}
return os;
}


TextQuery::TextQuery(ifstream& is) :file()
{
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
{
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);
}


ostream &print(ostream &os, const QueryResult &qr)
{
os << qr.sought << " occrus " << qr.lines->size() << " times " << endl;
qr.file.PRINT(os, qr.lines);
return os;
}


QueryResult OrQuery::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());
}


QueryResult AndQuery::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());
}


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 == end || *beg != n)
ret_lines->insert(n);
else if (beg != end)
++beg;
}
return QueryResult(rep(), ret_lines, result.get_file());
}


main函数:

using namespace std;


int main()
{
ifstream text("123.txt");//文本的位置和名字自己看着处理就好
if (!text)
{
cout << "Cannot open file!\n";
exit(1);
}
TextQuery tq(text);
Query q = ~Query("she");
auto result = q.eval(tq);
print(cout, result);
return 0;
}



注:没有完全实现书本上的实时查询功能,有能力的童鞋可以再试试

猜你喜欢

转载自blog.csdn.net/woyaoxuechengxu/article/details/52134330
今日推荐