C++之文本查询系统

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 ;
}

5.运行结果:

这里写图片描述

posted @ 2018-04-07 23:00  Tattoo_Welkin  阅读(282)  评论(0编辑  收藏  举报