C++Primer文本查询TextQuery

//《C++primer》P430
#include<vector>
#include<iostream>
#include<memory>
#include <set>
#include<map>
#include<string>
#include<fstream>
#include<sstream>
#include<algorithm>
using namespace std;
#ifndef MAKEPLURAL_H
#define MAKEPLURAL_H
inline
std::string make_plural(size_t ctr, const std::string &word, const std::string ending)
{
    return (ctr == 1) ? word : word + ending;
}
#endif
//    //文本查询P432
//        //在给定的一个文件中查询单词,并且输出单词所在行的行号、列表以及在文件中出现的次数
//
//        //1.当程序读取输入文件时,必须记住单词出现的每一行。所以,程序应该按行读取单词,并且将每一行分解成独立的单词;
//        //2.当程序输出时,(1)必须可以提取出每个单词所关联的行号;(2)行号必须升序且不重复;(3)必须可以打印出给定行号的文本
//
//}

//在具体写类成员之前那,先编写程序使用类
#if 0
void runQueries(ifstream &infile)
{
    TextQuery tq(infile); //保存文件,并建立map

    while (true)
    {
        cout << "enter word to look for,or to quit: " << endl;
        string s;
        //遇到文件结尾或者"q"时循环终止
        if (!(cin >> s) || s == "q") break;
        //指向查询并打印结果
        print(cout, tq.query(s)) << endl;
    }

}
#endif

class QueryResult;
class TextQuery
{
public:
    using line_no = std::vector<std::string>::size_type;
    TextQuery(std::ifstream& is);
    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::TextQuery(std::ifstream& is) :file(new vector<std::string>)
{
    std::string text;
    while (getline(is, text)) {
        file->push_back(text);
        int n = file->size() -1;//当前行号
        istringstream line(text); //将行文本分解为单词
        string word;
        while (line>>word)
        {
            auto &lines = wm[word];  //lines为每个单词对应set的引用
            if (!lines) {
                lines.reset(new set<line_no>); //分配一个新的set
            }
            lines->insert(n);  //将此行号插入到set中
        }
    }

}


class QueryResult {
    friend std::ostream& print(std::ostream&, const QueryResult&);
public:
    using line_no = std::vector<std::string>::size_type;
    QueryResult(std::string s,
        std::shared_ptr<std::set<line_no>> p,
        std::shared_ptr<std::vector<std::string>> f) :
        sought(s), lines(p), file(f) { }
private:
    string sought;
    shared_ptr<set<line_no>> lines;
    shared_ptr<vector<string>> file;
        
};

QueryResult TextQuery::query(const string &sought) const
{
    static shared_ptr<set<line_no>> nodata(new set<line_no>); //未找到sought,将返回一个指向此set的指针

    auto loc = wm.find(sought);//使用find查找,避免将单词添加到wm中
    if (loc == wm.end()) {
        return QueryResult(sought, nodata, file);
    }
    else {
        return QueryResult(sought, loc->second, file);
    }

}

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中的每个单词
    {
        os << "\t(line" << num + 1 << ")"
            << *(qr.file->begin() + num) << endl;
        return os;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值