/**
* 功能:使用标准库:文本查询程序
* 时间:2014年7月10日09:10:15
* 作者:cutter_point
*/
#include<iostream>
#include<map>
#include<set>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
using namespace std;
using line_no=vector<string>::size_type;
/**************************************
定义TextQuery类
**************************************/
class QueryResult; //为了定义函数query的返回类型,前向申明
class TextQuery
{
public:
TextQuery(ifstream&);
QueryResult query(const string&) const;
private:
shared_ptr<vector<string>> file; //输入文件
//每个单词到它所在的行数的集合映射
map<string, shared_ptr<set<line_no>>> wm;
};
/*
读取输入文件并建立单词到行号的映射
*/
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); //将文本分解为单词,istringstream是以空格为结束
string word;
while(line>>word) //对应每行的每个单词
{
//如果单词不再wm中,就以它为下标在wm中添加一项
auto &lines=wm[word]; //lines是一个shared_ptr,有了key值,但是没有value
if(!lines) //当我们第一次遇到这个单词的时候,此指针为空
{
lines.reset(new set<line_no>); //吧a指向的内置指针b,否则置空,a.reset(b)
}
lines->insert(n); //将此行插入set中
}
}
}
/**************************************
QueryResult类
**************************************/
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f):sought(s),lines(p),file(f){}
private:
string sought; //查询单词
shared_ptr<set<line_no>> lines; //出现的行号
shared_ptr<vector<string>> file; //输入文件
};
//make_plural判断是否有元素的函数
inline string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word+ending : ending;
}
/*
友元函数实现
*/
ostream& print(ostream & os, const QueryResult & qr)
{
//如果找到了单词,打印出现的次数,和出现的位置
//如果找到了单词,打印出现的次数
os<<qr.sought<<" occurs "<<qr.lines->size()<<" "<<make_plural(qr.lines->size(), "time", "s")<<endl;
//打印单词出现的每一行
for(auto num : *qr.lines) //对set中每个单词
{
//避免重0行开始给用户带来困惑
os<<"\t(line "<<num<<")"<<*(qr.file->begin()+num-1)<<endl;
}
return os;
}
/*
用QueryResult中的数据定义TextQuery中的函数
*/
QueryResult
TextQuery::query(const string &sought) const
{
//如果未找到sought,我们将返回一个指向此set的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//使用find而不是下标运算来查找单词,避免将单词添加进去了
auto loc=wm.find(sought);
if(loc == wm.end())
return QueryResult(sought, nodata, file); //未找到
else
return QueryResult(sought, loc->second, file);
}
/**************************************
使用TextQuery类
**************************************/
void runQueries(ifstream &infile)
{
//infile是一个ifstream,指向我们要处理的文件
TextQuery tq(infile); //保存文件并建立查询map
//与用户交互:提示用户输入要查询的单词,完成查询并打印结果
while(true)
{
cout<<"enter word to look for , or q to quit: ";
string s;
//若遇到文件结尾或输入'q'时结束循环
if(!(cin>>s) || s == "q")
break; //指向查询并打印结果
print(cout, tq.query(s))<<endl;
}
}
int main()
{
ifstream infile("test.txt");
runQueries(infile);
return 0;
}
【足迹C++primer】41、文本查询程序,布布扣,bubuko.com
【足迹C++primer】41、文本查询程序