1. 整体需求
使用标准库实现一个简单的文本查询系统。允许用户在一个给定的文件中查询单词。查询结果是单词在文件中出现的次数以及所在行的列表。如果一个单词在一行中出现多次,该行也只列出一次,但是出现的次数得统计在内。行序号按照升序输出。
2. 程序需要完成的功能和实现效果
需要完成的功能:
1.从文件按行读入信息,并将单词分离开来。
2.必须提取到每一个单词所出现的行号
3.行号按照升序排列且不重复
4.必须打印给定文本中的文字
5.必须统计出一个单词所出现的所有次数
实现效果:
3. 程序架构设计
<1> 因为要打印文本中所出现的文字,所以就意味着需要保存 ,那么我们选择vector<string>
来保存它,另外行号还可以作为它的下标来提取文字。
<2>使用istringstream
来分离单词 。
<3>对于每一个单词,我们使用一个multiset来保存它在文本中出现的行号 。这就自然保证了升序的特点,至于重复的问题,我们只要在输出时解决一下就行了,反正multiset中只存储了行号,不会有很多重复的数据 。
<4>使用一个map来将每个单词和它所对应的set关联起来,以便提取。
<5> 使用智能指针!! 这是为什么呐?因为QueryResult 要查询到的数据原先全在 TextQuery 中的,如果将其拷贝到 QueryResult 类中,会花费很多的时间,那么我们通过指针来减少这种花费。考虑到两个对象的同步问题(比如在QueryResult 用到TextQuery之前,TextQuery对象已经销毁了),我们通过使用智能指针来解决这种矛盾 。
4.实现代码:
/*test.txt 文件中的内容 */
liu
sheng
xi
zui
shuai
哦哦
liu
liu liu liu
lu
liy
bnglbn
bkngbgmn blnblgnb ;ng;f f;gfg; nfnbdn
bbdnbkkbnbnonb
bntlobntol
liu liu
liu
liull
gmrlnrgliu
liu shen xi
/*************************************************************************
> File Name: main.cpp
> Author:
> Mail:
> Created Time: 2018年04月01日 星期日 11时42分31秒
************************************************************************/
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<memory> //shared_ptr
#include<fstream>
#include<sstream> //istringstream
using namespace std ;
using line_no = vector<string>::size_type ; // 行号
class DegbugDelete{ // 我们在这里自定义一个删除器
public:
DegbugDelete(ostream &s= cerr):os(s){ }
template<typename T>
void operator()(T *p) const{
os<< "deleteing shared_ptr " << endl ;
delete p;
}
private:
ostream &os ;
};
class QueryResult{
friend ostream& print(ostream& os , const QueryResult &TT ){
os << TT.sought << " occurs " << TT.lines->size() << " times "<< endl ;
if(TT.lines->size() == 0 )
return os ;
auto tag = TT.lines->begin() ;
decltype(tag) temp = tag ;
tag++ ;
while( temp != TT.lines->end()){
if( *tag != *temp ){
os << " 行 "<<*temp+1 << " : " << (*TT.file)[*temp] << endl ;
}
temp++ ;
tag++ ;
}
return os ;
}
public:
QueryResult() = default ;
QueryResult(string s ,
shared_ptr<multiset<line_no>> p ,
shared_ptr<vector<string>> f ):sought(s),lines(p),file(f){}
private:
string sought ;
shared_ptr<multiset<line_no>> lines ;
shared_ptr<vector<string>> file ;
};
class TextQuery {
public:
TextQuery(ifstream &infile): file ( new vector<string> ,DegbugDelete() ) //定义删除器
{
//读取文件数据到 vector<string> 中 ,分离各个单词
string text ,word ;
while( getline(infile,text )){
file->push_back(text) ;
int n = file->size() - 1 ;
istringstream line(text) ;
while( line >> word ){
auto &lines = wm[word] ; //当我们这样使用时,加入没有的单词,就已经创建了,只不过指针是空的而已
if( ! lines )
lines.reset( new multiset<line_no> ,DegbugDelete() ) ; // 初始化 shared_ptr
lines->insert(n) ; //插入n
}
}
}
QueryResult query( const string &temp ) const {
static shared_ptr<multiset<line_no>> nodata(new multiset<line_no>,DegbugDelete()) ;
//emmmm ,如果不构造此空 set 使用默认的 default,就会出现段错误
auto loc = wm.find(temp);
if( loc == wm.end() ){
cout << temp << " is not in test.txt file " << endl ;
return QueryResult(temp ,nodata ,file);
}
else
return QueryResult(temp, loc->second,file ) ;
}
private:
shared_ptr< vector<string> > file ; //输入文件 ,智能指针
map<string,shared_ptr<multiset<line_no> > > wm ; //每一个单词到行号的映射
};
int fun(ifstream &infile){
const TextQuery tq(infile);
string word ;
while(1) {
cout << " 请 输 入 你 想 要 查 询 的 单 词 :" ;
cin >> word ;
if(word == "q")
return 0 ;
print(cout,tq.query(word)) << endl ;
}
return 0 ;
}
int main(void){
cout << " 你将在文件:test.txt 中查询你想要查询的单词 \n\n" << endl ;
ifstream infile("test.txt");
if( !infile.is_open()){
cout << " 未 成 功 打 开 文 件!!" << endl ;
return -1 ;
}
fun(infile);
infile.close() ;
return 0 ;
}