【足迹C++primer】41、文本查询程序

/**
* 功能:使用标准库:文本查询程序
* 时间: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、文本查询程序,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。