1. 程式人生 > >c++ primer 5ed 15.9文字查詢程式再探

c++ primer 5ed 15.9文字查詢程式再探

標頭檔案:

#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;
}



注:沒有完全實現書本上的實時查詢功能,有能力的童鞋可以再試試