文本查询程序再探(C++primer5th)

来源:互联网 发布:淘宝拒签后怎么处理 编辑:程序博客网 时间:2024/06/05 07:46

在文本查询程序的基础上添加了更多功能。
单词查询:查询单词出现的次数(一行出现多次只算一次),并打印出所在的行。
逻辑查询(~,&,|),支持混合使用这些运算符。
通过一个接口类Query隐藏整个实现的继承体系,同时被用户代码和类实现代码使用。这种做法可以将接口与实现分离,Query内存储一个指向实际实现类的指针。

首先是文本查询程序中的原代码,只给QueryResult.hpp添加了新的成员函数
TextQuery.hpp

#include <memory>#include <vector>#include <string>#include <fstream>#include <set>#include <map>#include <sstream>using namespace std;class QueryResult;class TextQuery{public:    using line_no=vector<string>::size_type;    TextQuery(ifstream & is);    QueryResult query(const string & word)const;private:    shared_ptr<vector<string>> file;    map<string,shared_ptr<set<line_no>>> wm;};

QueryResult.hpp

#include "TextQuery.hpp"#include <iostream>class QueryResult{public:    friend ostream & print(ostream & os,const QueryResult & sought);    QueryResult(const string & s,shared_ptr<set<TextQuery::line_no>> p,                shared_ptr<vector<string>> f):    sought(s),lines(p),file(f){}    shared_ptr<vector<string>> getFile()    {        return file;    }    set<TextQuery::line_no>::iterator begin()    {        return lines->begin();    }    set<TextQuery::line_no>::iterator end()    {        return lines->end();    }private:    string sought;    shared_ptr<vector<string>> file;    shared_ptr<set<TextQuery::line_no>> lines;};
#include "TextQuery.hpp"#include "QueryResult.hpp"TextQuery::TextQuery(ifstream &is):file(new vector<string>){    string text;    while (getline(is,text))                    //从文本中读取一行    {        file->push_back(text);                  //每行作为一个元素存入vector        size_t n = file->size() - 1;               //行号,下标        istringstream line(text);        string word;        while (line>>word)                      //从每行中读取单个单词        {            auto &lines = wm[word];             //map的下标运算符,如果关键字不存在,则创建一个新元素。            //其value为空指针            //lines是引用,改变它也会改变智能指针            if (!lines)            {                lines.reset(new set<line_no>);  //第一次遇到word为空指针,因此让他指向新的set            }            lines->insert(n);                   //将行号插入set,如果重复则不执行任何操作        }    }}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);           //如果没找到,返回空set    }    else    {        return QueryResult(sought, loc->second, file);      //返回指向set的指针    }}

抽象基类,提供接口,需要将析构函数声明为虚函数
QueryBase.hpp

#include "QueryResult.hpp"class QueryBase{    friend class Query;//调用虚函数protected:    using line_no=TextQuery::line_no;    virtual ~QueryBase()=default;private:    virtual QueryResult eval(const TextQuery&)const=0;    virtual string rep()const=0;};class WordQuery:public QueryBase{    friend class Query;//调用构造函数private:    WordQuery(const string & s):queryWord(s){}    QueryResult eval (const TextQuery & t)const override    {return t.query(queryWord);}    string rep()const override    {return queryWord;}    string queryWord;};

接口类,写代码时在头文件定义operator<<()函数导致多重定义,加上Inline后问题解决。
Query.hpp

#include "QueryBase.hpp"class Query{    friend Query operator~(const Query &);//调用私有构造函数    friend Query operator|(const Query &,const Query &);    friend Query operator&(const Query &,const Query &);public:    Query(const string & s):q(new WordQuery(s)){}    QueryResult eval(const TextQuery &t)const    {return q->eval(t);}    string rep()const    {return q->rep();}private:    Query(shared_ptr<QueryBase> query):q(query){}    shared_ptr<QueryBase> q;};inline ostream & operator<<(ostream & os,const Query & query){    return os<<query.rep();}

NotQuery.hpp

#include "Query.hpp"class NotQuery:public QueryBase{    friend Query operator~(const Query &);    NotQuery(const Query & q):query(q){}    string rep()const override    {return "~("+query.rep()+")";}    QueryResult eval(const TextQuery & text)const override;    Query query;};inline Query operator~(const Query & operand){    return shared_ptr<QueryBase>(new NotQuery(operand));}

具体实现,和书上不完全一样
NotQuery.cpp

#include "NotQuery.hpp"QueryResult NotQuery::eval(const TextQuery & text)const{    auto retLines=        make_shared<set<line_no>>();    auto result=query.eval(text);    for(int i=0;i<result.getFile()->size();++i)    {        retLines->insert(i);    }    auto itr=result.begin();    auto ret=retLines->begin();    while(itr!=result.end()&&ret!=retLines->end())    {        if(*ret==*itr)        {            //erase的两种使用方式            retLines->erase(ret++);            //ret=retLines->erase(ret);            ++itr;        }        else            ++ret;    }    return QueryResult(rep(),retLines,result.getFile());}

BinaryQuery.hpp

#include "Query.hpp"class BinaryQuery:public QueryBase{protected:    BinaryQuery(const Query & lt,const Query & rt,string s):    lhs(lt),rhs(rt),opSym(s){}    string rep()const override    {        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,"&"){}    QueryResult eval(const TextQuery &)const override;};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 override;};inline Query operator|(const Query & lhs,const Query & rhs){    return shared_ptr<QueryBase>(new OrQuery(lhs,rhs));}inline Query operator&(const Query & lhs,const Query & rhs){    return shared_ptr<QueryBase>(new AndQuery(lhs,rhs));}

求交集时可以用书上提供的方法和我自己写的方法。
BinaryQuery.cpp

#include "BinaryQuery.hpp"//#include <algorithm>QueryResult OrQuery::eval(const TextQuery & text)const{    auto left=lhs.eval(text),right=rhs.eval(text);    auto retLines=        make_shared<set<line_no>>(left.begin(),left.end());    retLines->insert(right.begin(),right.end());    return QueryResult(rep(),retLines,left.getFile());}QueryResult AndQuery::eval(const TextQuery & text)const{    auto left=lhs.eval(text),right=rhs.eval(text);    auto retLines=        make_shared<set<line_no>>();    auto lt=left.begin(),rt=right.begin();    while(lt!=left.end()&&rt!=right.end())    {        if(*lt<*rt)            ++lt;        else if(*rt<*lt)            ++rt;        else        {            retLines->insert(*lt);            ++lt;            ++rt;        }    }   // set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*retLines, retLines->begin()));    return QueryResult(rep(),retLines,left.getFile());}

main.cpp

#include "Query.hpp"#include "NotQuery.hpp"#include "BinaryQuery.hpp"int main(){    void runQuery(ifstream &file);    ifstream file("file.txt");    runQuery(file);    return 0;}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;}void runQuery(ifstream &file){    TextQuery tq(file);    while (true)    {        cout << "enter word to look for"<<endl;        string s1,s2,s3;        cin>>s1>>s2>>s3;        Query q0(s1);        Query q=Query(s1)&Query(s2)|Query(s3);        Query q1=~Query(s1);        Query q2=Query(s1)|Query(s2);        print(cout, q0.eval(tq)) << endl;        print(cout, q.eval(tq)) << endl;        print(cout, q1.eval(tq)) << endl;        print(cout, q2.eval(tq)) << endl;    }}

测试示例
文本
When you are old and grey and full of sleep
And nodding by the fire take down this book
And slowly read and dream of the soft look
Your eyes had once and of their shadows deep
How many loved your moments of glad grace
And loved your beauty with love false or true
But one man loved the pilgrim Soul in you
And loved the sorrows of your changing face
And bending down beside the glowing bars
Murmur a little sadly how Love fled
And paced upon the mountains overhead
And hid his face amid a crowd of stars

程序运行
enter word to look for
And you of
And occurs 7 times
(line2) And nodding by the fire take down this book
(line3) And slowly read and dream of the soft look
(line6) And loved your beauty with love false or true
(line8) And loved the sorrows of your changing face
(line9) And bending down beside the glowing bars
(line11) And paced upon the mountains overhead
(line12) And hid his face amid a crowd of stars

((And & you) | of) occurs 6 times
(line1) When you are old and grey and full of sleep
(line3) And slowly read and dream of the soft look
(line4) Your eyes had once and of their shadows deep
(line5) How many loved your moments of glad grace
(line8) And loved the sorrows of your changing face
(line12) And hid his face amid a crowd of stars

~(And) occurs 5 times
(line1) When you are old and grey and full of sleep
(line4) Your eyes had once and of their shadows deep
(line5) How many loved your moments of glad grace
(line7) But one man loved the pilgrim Soul in you
(line10) Murmur a little sadly how Love fled

(And | you) occurs 9 times
(line1) When you are old and grey and full of sleep
(line2) And nodding by the fire take down this book
(line3) And slowly read and dream of the soft look
(line6) And loved your beauty with love false or true
(line7) But one man loved the pilgrim Soul in you
(line8) And loved the sorrows of your changing face
(line9) And bending down beside the glowing bars
(line11) And paced upon the mountains overhead
(line12) And hid his face amid a crowd of stars

enter word to look for

And your by
And occurs 7 times
(line2) And nodding by the fire take down this book
(line3) And slowly read and dream of the soft look
(line6) And loved your beauty with love false or true
(line8) And loved the sorrows of your changing face
(line9) And bending down beside the glowing bars
(line11) And paced upon the mountains overhead
(line12) And hid his face amid a crowd of stars

((And & your) | by) occurs 3 times
(line2) And nodding by the fire take down this book
(line6) And loved your beauty with love false or true
(line8) And loved the sorrows of your changing face

~(And) occurs 5 times
(line1) When you are old and grey and full of sleep
(line4) Your eyes had once and of their shadows deep
(line5) How many loved your moments of glad grace
(line7) But one man loved the pilgrim Soul in you
(line10) Murmur a little sadly how Love fled

(And | your) occurs 8 times
(line2) And nodding by the fire take down this book
(line3) And slowly read and dream of the soft look
(line5) How many loved your moments of glad grace
(line6) And loved your beauty with love false or true
(line8) And loved the sorrows of your changing face
(line9) And bending down beside the glowing bars
(line11) And paced upon the mountains overhead
(line12) And hid his face amid a crowd of stars

enter word to look for

原创粉丝点击