感觉这个例子很锻炼面向对象思想,所以还是写下来吧
Query_base.h
#pragma once
# include"TextQuery.h"
# include"QueryResult.h"
# include<string>
//这是一个抽象基类,具体的查询类型从中派生,所有成员都是private的
class Query_base
{
friend class Query;
protected:
using line_no = TextQuery::line_no; //用于eval函数
virtual ~Query_base() = default;
private:
//eval返回与当前Query匹配的QueryResult
virtual QueryResult eval(const TextQuery &)const = 0;
virtual std::string rep()const = 0;
};
Query.h
#pragma once
# include<string>
# include"QueryResult.h"
# include"TextQuery.h"
# include"Query_base.h"
# include<iostream>
//这是一个管理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:
Query(const std::string&);//构建一个新的WordQuery
//接口函数:调用对应的Query_base操作
QueryResult eval(const TextQuery&t)const;
std::string rep()const;
private:
Query(std::shared_ptr<Query_base> query);
std::shared_ptr<Query_base> q;
};
Query.cpp
# include"Query.h"
# include"WordQuery.h"
# include<string>
# include<iostream>
QueryResult Query::eval(const TextQuery&t)const
{
return q->eval(t);
}
std::string Query::rep()const
{
return q->rep();
}
Query::Query(const std::string&s):q(new WordQuery(s))
{}
std::ostream&operator<<(std::ostream&os, const Query&query)
{
//Query::rep通过它的Query_base指针对rep()进行了虚调用
return os << query.rep();
}
Query::Query(std::shared_ptr<Query_base> query) :q(query) {}
TextQuery.h
# pragma once
# include"QueryResult.h"
# include<vector>
# include<fstream>
# include<memory>
# include<map>
# include<set>
class QueryResult;//为了定义函数query的返回类型,这个定义是必须的
class TextQuery
{
public:
using line_no = std::vector<std::string>::size_type;
TextQuery(std::ifstream &);
QueryResult query(const std::string &)const;
private:
std::shared_ptr<std::vector<std::string>> file; //输入文件
std::map<std::string,
std::shared_ptr<std::set<line_no>>> wm;
};
TextQuery.cpp
# include"TextQuery.h"
# include<vector>
# include<string>
# include<sstream>
# include"QueryResult.h"
class QueryResult;
using namespace std;
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) //对行中每个单词
{
//如果单词不在wm中,以之为下标在wm中添加一项
auto &lines = wm[word];//lines是一个sharred_ptr
if (!lines) //在我们第一次遇到这个单词时,此指针为空
lines.reset(new set < line_no>);//分配一个新的set
lines->insert(n); //将此行号插入set中
}
}
}
QueryResult TextQuery::query(const string &sought)const
{
//如果未找到sought,我们将返回一个指向此set的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//使用find而不是下标运算符来查找单词,避免将单词添加到wm中
auto loc = wm.find(sought);
if (loc == wm.end())
return QueryResult(sought, nodata, file); //未找到
else return
QueryResult(sought, loc->second, file);
}
QueryResult.h
# pragma once
# include<iostream>
# include"TextQuery.h"
# include<memory>
# include<set>
# include<vector>
# include<string>
class QueryResult
{
friend std::ostream& print(std:: ostream &, const QueryResult&);
public:
using size = std::vector<std::string>::size_type;
QueryResult(std::string s,
std::shared_ptr<std::set<size>> p,
std::shared_ptr<std::vector<std::string>> f);
std::set<size>::iterator begin();
std::set<size>::iterator end();
std::shared_ptr<std::vector<std::string>> get_file();
private:
std::string sought;//查询单词
std::shared_ptr<std::set<size>> lines;//出现的行号
std::shared_ptr<std::vector<std::string>> file; //输入文件
};
QueryResult.cpp
# include"QueryResult.h"
# include"TextQuery.h"
using size = std::vector<std::string>::size_type;
QueryResult::QueryResult(std::string s,
std::shared_ptr<std::set<size>> p,
std::shared_ptr<std::vector<std::string>> f):sought(s), lines(p), file(f)
{}
std::set<size>::iterator QueryResult::begin()
{
return this->lines->begin();
}
std::set<size>::iterator QueryResult::end()
{
return this->lines->end();
}
std::shared_ptr<std::vector<std::string>> QueryResult::get_file()
{
return this->file;
}
WordQuery.h
#pragma once
# include"Query_base.h"
# include<string>
class WordQuery:public Query_base
{
friend class Query; //Query使用WordQuery构造函数
WordQuery(const std::string &s);
//具体的类:WordQuery将定义所有继承+而来的纯虚函数
QueryResult eval(const TextQuery&t)const;
std::string rep()const;
std::string query_word; //要查找的单词
};
WordQuety.cpp
# include"WordQuery.h"
WordQuery::WordQuery(const std::string &s) :query_word(s) {}
//具体的类:WordQuery将定义所有继承而来的纯虚函数
QueryResult WordQuery::eval(const TextQuery&t)const
{
return t.query(query_word);
}
std::string WordQuery::rep()const
{
return query_word;
}
BinaryQuery.h
# pragma once
# include"Query.h"
# include"Query_base.h"
class BinaryQuery:public Query_base
{
protected:
BinaryQuery(const Query &l, const Query &r, std::string s);
//抽象类:BinaryQuery不定义eval
std::string rep()const;
Query lhs,rhs; //右侧和左侧运算对象
std::string opSym; //运算符的名字
};
BinaryQuery.cpp
# include"BinaryQuery.h"
BinaryQuery::BinaryQuery(const Query &l, const Query &r, std::string s) :
lhs(l), rhs(r), opSym(s) {}
std::string BinaryQuery::rep()const
{
return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
}
AndQuery.h
#pragma once
# include"BinaryQuery.h"
class AndQuery:public BinaryQuery
{
friend Query operator&(const Query&, const Query&);
AndQuery(const Query&left, const Query&right);
//具体的类:AndQuery继承了rep并且定义了其他纯虚函数
QueryResult eval(const TextQuery&)const;
};
AndQuery.cpp
# include"AndQuery.h"
# include<set>
# include<memory>
# include<algorithm>
# include<iterator>
AndQuery::AndQuery(const Query&left, const Query&right) :
BinaryQuery(left, right, "&") {}
Query operator&(const Query&lhs, const Query &rhs)
{
return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
QueryResult AndQuery::eval(const TextQuery&text)const
{
//通过Query运算对象进行的虚调用,以获得运算对象的查询结果set
auto left = lhs.eval(text), right = rhs.eval(text);
//保存left和right的交集的set
auto ret_lines = std::make_shared<std::set<line_no>>();
//将两个范围的交集写入一个目的迭代器中
//本次调用的目的迭代器向ret添加元素
std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
inserter(*ret_lines, ret_lines->begin()));
return QueryResult(rep(), ret_lines, left.get_file());
}
OrQuery.h
#pragma once
# include"BinaryQuery.h"
class OrQuery :public BinaryQuery
{
friend Query operator|(const Query&, const Query&);
OrQuery(const Query&left, const Query&right);
//具体的类:AndQuery继承了rep并且定义了其他纯虚函数
QueryResult eval(const TextQuery&)const;
};
OrQuery.cpp
# include"OrQuery.h"
# include<memory>
# include<set>
# include"BinaryQuery.h"
# include"Query_base.h"
# include"Query.h"
OrQuery::OrQuery(const Query&left, const Query&right) :
BinaryQuery(left, right, "|") {}
QueryResult OrQuery::eval(const TextQuery&text)const
{
//通过Query成员lhs和rhs进行的虚调用
//调用eval返回每个运算对象的QueryResult
auto right = rhs.eval(text), left = lhs.eval(text);
//将左侧运算对象的行号拷贝到结果Set中
auto ret_lines = std::make_shared<std::set<line_no>>(left.begin(), left.end());
//插入右侧运算对象所得的行号
ret_lines->insert(right.begin(), right.end());
//返回一个新的QueryResult,它表示lhs和rhs的并集
return QueryResult(rep(), ret_lines, left.get_file());
}
Query operator|(const Query&lhs, const Query &rhs)
{
return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
NotQuery.h
#pragma once
# include"Query_base.h"
# include"Query.h"
class NotQuery:public Query_base
{
friend Query operator~(const Query&);
NotQuery(const Query&q);
//具体的类:NotQuery将定义所有继承而来的纯虚函数
std::string rep()const;
QueryResult eval(const TextQuery&) const;
Query query;
};
NotQuery.cpp
# include"NotQuery.h"
# include<memory>
# include<set>
# include"QueryResult.h"
class QueryResult;
NotQuery::NotQuery(const Query&q) :query(q) {}
std::string NotQuery::rep()const
{
return "~(" + query.rep() + ")";
}
QueryResult
NotQuery::eval(const TextQuery&text)const
{
auto result = query.eval(text);
auto ret_lines=std::make_shared<std::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());
}
Query operator~(const Query&operand)
{
//return std::shared_ptr<Query_base>(new NotQuery(operand));
//等价于:
std::shared_ptr<Query_base> tmp(new NotQuery(operand));
return Query(tmp);
}
先来查找单个单词,main.cpp
# include<iostream>
# include<fstream>
# include<string>
# include"Query.h"
# include"QueryResult.h"
# include"TextQuery.h"
# include"WordQuery.h"
using namespace std;
std::ostream& print(std::ostream &, const QueryResult&);
std::string make_plural(size_t i, const std::string &word, const std::string &end)
{
return i == 1 ? word : word + end;
}
int main()
{
std::ifstream fin("E:\\项目\\c++\\文本查询程序2\\文本查询程序2\\file.txt");
TextQuery text(fin);
Query a1("windows");
Query a2("class");
Query b1=~a1;
Query b2 = a1&a1;
Query b3 = a1 | a1;
auto s = a1.rep();
cout << s << endl;
const auto result = a1.eval(text);
print(std::cout, result);
fin.close();
system("pause");
return 0;
}
std::ostream& print(std::ostream &os, const QueryResult&qr)
{
os << qr.sought << " occus " << qr.lines->size() << " "\
<< make_plural(qr.lines->size(), "time", "s") << std::endl;
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ")\t" << *(qr.file->begin() + num) << std::endl;
return os;
}
查找单词windows:
接下来查找没有单词a1的:
查找同时出现a1和a2:
查找出现a1或a2: