文本查询程序-类

// 文本查询程序-类.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<string>
#include<iostream>
#include<memory>
#include<sstream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<iterator>
#include<fstream>

using namespace std;

class QueryResult//储存查询结果并输出!
{
public:
    using line_no = vector<string>::size_type;
    QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f) :find_word(s), lines(p), file(f) {}
    friend ostream &print(ostream &os, const QueryResult &qr);
    set<line_no>::const_iterator begin()const { return lines->cbegin(); }
    set<line_no>::const_iterator end()const { return lines->cend(); }
    const shared_ptr<vector<string>> get_file()const { return file; }

private:
    string find_word;
    shared_ptr<set<line_no>> lines;
    shared_ptr<vector<string>> file;
};

ostream &print(ostream &os, const QueryResult &qr)
{
    os << qr.find_word << " 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() = default;
    TextQuery(istream &in) { read(in); }
    void read_from_file(istream &in) { read(in); }
    QueryResult query(const string &find_word) const;                       //创建queryresult对象!

private:
    void read(istream &in);
    shared_ptr<vector<string>> file = make_shared<vector<string>>();            // 如果创建空的只能指针,必须进行绑定(初始化)才可以使用!为什么不能使用new?
    map<string, shared_ptr<set<line_no>>> wm;                               //共享数据,避免拷贝增加计算量!
};

QueryResult TextQuery::query(const string &find_word) const
{
    if (wm.find(find_word) == wm.cend())
    {
        return QueryResult(find_word, nullptr, file);
    }
    else
    {
        return QueryResult(find_word, wm.at(find_word), file);
    }
}

void TextQuery::read(istream &in)
{
    string text;
    while (getline(in, text))
    {
        file->push_back(text);
        int n = file->size() - 1;
        istringstream line(text);
        string word;
        while (line >> word)
        {
            auto &lines = wm[word];
            if (!lines)                         //如果为空指针,则重新指向new set<line_no>
                lines.reset(new set<line_no>);
            lines->insert(n);
        }
    }
}

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 string rep() const = 0;
};

class WordQuery :public Query_base
{
    friend class Query;
    WordQuery(const string &s) :query_word(s) {}//Query的构造函数要调用此构造函数,因此必须前置!
    QueryResult eval(const TextQuery &t)const { return t.query(query_word); }
    string rep()const { return query_word; }
    string 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 string &s) :q(new WordQuery(s)) {}                      //创建wordQuery指针对象,用Query_Base指针指向!
    QueryResult eval(const TextQuery &t)const { return q->eval(t); }
    string rep()const { return q->rep(); }

    friend ostream &operator<<(ostream &os, const Query &query);
private:
    Query(shared_ptr<Query_base> query):q(query){}
    shared_ptr<Query_base> q;
};

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

class NotQuery :public Query_base
{
    friend Query operator~(const Query&);
    NotQuery(const Query &q):query(q){}
    string rep()const { return "~(" + query.rep() + ")"; }
    QueryResult eval(const TextQuery&)const;
    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){}
    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, "&") {};
    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,"|") {}
    QueryResult eval(const TextQuery &)const;
};
inline Query operator|(const Query &lh, const Query &rh)
{
    return shared_ptr<Query_base>(new OrQuery(lh, rh));
}
QueryResult OrQuery::eval(const TextQuery &text)const
{
    using line_no = vector<string>::size_type;
    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());       //set.inser(b,e)
    return QueryResult(rep(), ret_lines, left.get_file());

}

QueryResult AndQuery::eval(const TextQuery &text)const
{
    using line_no = vector<string>::size_type;
    auto left = lhs.eval(text), right = rhs.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()));//插入迭代器inserter
    return QueryResult(rep(),ret_lines,left.get_file());
}

QueryResult NotQuery::eval(const TextQuery &text)const
{
    using line_no = vector<string>::size_type;
    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());
}

int main()
{
    string filename = "C:\\Users\\winack\\Documents\\Visual Studio 2017\\Projects\\文本查询程序-My-继承、\\123.txt";
    ifstream file(filename);
    TextQuery info(file);

    Query q = Query("is") & Query("the") | Query("have");
    //cout << q;
    print(cout, q.eval(info));
    q = Query("and");//Query自动合成拷贝构造函数!
    print(cout, q.eval(info));

    return 0;
}

推荐阅读更多精彩内容