使用标准库:文本查询程序

C++ Primer 5th 第12章动态内存
使用标准库:文本查询程序
程序名称:文本查询程序
程序功能:允许用户在一个给定文件中查询单词,查询结果是单词在文件
中出现的次数及其所在行的列表.如果一个单词在一行中出现多次,此
行只列出一次。行会按照升序排列输出
输出格式:
element occurs 112 times
(line 36) Aset element contains only a key;

程序需完成的操作:

  1. 当程序读入一个输入文件时,必须记住单词出现的每一行。因此,
    程序需要逐行读取输入文件,并将每一行分解为独立的单词
  2. 当程序生成输出时,
    1)必须能够提取每个单词所关联的行号
    2)行号必须按升序出现且无重复
    3)必须能打印给定行号中的文本
    程序实现:
    1.使用vector<string>来保存整个输入文件的一份拷贝。输入文件中
    的每一行保存为vector<string>中的一个元素。当需要打印一行时,可
    用行号作为下标提取行文本
    2.使用isstringstream来将每行分解为单词。
    3.使用一个set来保存每个单词在输入文件中出现的行号。这保证了每行只
    出现一次且行号按升序保存
    4.使用一个map来将每个单词与它出现的行号set关联起来。
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <memory>
#include <sstream>
#include <set>
#include <map>
#include <stdexcept>
using namespace std;


/*
QueryResult类:
保存查询结果:包括查询的单词
行号集合 和 文本拷贝 指针
操作:
定义print为类的友元函数
构造函数接受一个
*/
/*
TextQuery类:
数据成员:2个成员vector和map分别用来保存输入文件的文本,map用来
关联每个单词和它出现的行号的set
查询操作:返回给定单词的查询结果
*/
using line_no = vector<string>::size_type;
string make_plural(size_t ctr, const string& word,
            const string& ending);
class QueryResult; //为了定义query的返回类型,提要提前声明,告知编译器
class TextQuery {
public:
    TextQuery(ifstream &);
    QueryResult query(const string& word);
//    ~TextQuery();
private:
    shared_ptr<vector<string>> file;
    map<string, shared_ptr<set<line_no>>> wm;//给定单词到指向行集合智能指针的映射
};

class QueryResult {
    friend ostream& print(ostream& os, const QueryResult& result);
public:
    QueryResult(string, shared_ptr<vector<string>>,
                shared_ptr<set<line_no>>);
//    ~QueryResult();
private:
    string sought;//保存要查询的单词
    shared_ptr<vector<string>> file;//指向保存输入文件的指针
    shared_ptr<set<line_no>> lines;//指向保存行号的set
};
void runQueries(ifstream& infile) {
    //infile是一个ifsteram
    TextQuery tq(infile); //保存文件并建立查询map
    //与用户交互:提示用户输入要查询的单词,完成查询并打印结果
    while (true) {
        cout << "enter word to look for, or q to quit: ";
        string s;
        if (!(cin >> s ) || s == "q") {
            break;
        }
        //指向查询并打印结果
        print(cout, tq.query(s)) << endl;
    }
}
//TextQuery 构造函数
//读取输入文件并建立单词到行号的映射
TextQuery::TextQuery(ifstream& is): file(new vector<string>) {
    string Text;
    while (getline(is, Text)) {             //对每行文本进行操作
        file->push_back(Text);              //保存此行文本
        line_no n = file->size()-1;         //当前行号 = 保存每行文本的vector的大小-1
        istringstream line(Text);           //string输入流
        string word;
        while (line >> word) {
            //map<string, shared_ptr<set<line_no>>> wm;
            auto &lines = wm[word];         // line是一个shared_ptr;
            if (!lines) {                   //第一次遇见该单词,指针为空
                /*reset是智能指针的成员函数,
                shared_ptr<T> p.reset(q) 另p指向q
                */
                lines.reset(new set<line_no>); //分配一个新的set
            }
            lines->insert(n);//将本单词出现的行号插入到行号集合中
        }
    }
}
//TextQuery 查询操作query,返回指向给定单词所在行号的集合 和 输入文件的智能指针
QueryResult TextQuery::query(const string &sought) {
    //如果没有找到sought,返回一个指向此set的指针(空)
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    //使用下标运算符来查找单词,可能会将不存在映射的关系的单词强行加入
    //使用find而不是下标运算符来查找单词,避免将单词添加到wm中
    auto loc = wm.find(sought);
    if (loc == wm.end()) {
        //Effective C++ 必须返回对象时,别妄想返回其reference
        return QueryResult(sought, file, nodata);
    } else {
        return QueryResult(sought, file, loc->second);
    }
}
//QueryResult的构造函数唯一任务就是将参数保存到对应的数据成员中
QueryResult::QueryResult(string word, shared_ptr<vector<string>> file,
                         shared_ptr<set<line_no>> lines): sought(word),
    file(file), lines(lines) {
}
//QueryResult 的友元函数, 赋予其访问参数QueryResule的私有数据成员
//打印result
ostream& print(ostream& os, const QueryResult& result) {
    //string sought;//保存要查询的单词
    //shared_ptr<vector<string>> file;//指向保存输入文件的指针
    //shared_ptr<set<line_no>> lines;//指向保存行号的set
    //make_plural函数是根据第一个参数的大小,确定是输出time 还是 times
    os << result.sought << " occurs " << result.lines->size() << " "
       << make_plural(result.lines->size(), "time", "s") << endl;
    for (auto num : *result.lines) {
        os << "\t(line " << num + 1 << ")"
           //file->begin()+num 即为file指向的vector
           //中第num个元素的位置,解引用是所在行号对应的输入文本
           << *(result.file->begin() + num) << endl;
    }
}
string make_plural(size_t ctr, const string& word,
                   const string& ending) {
    return (ctr > 1 ) ? word + ending : word;
}
//TextQuery::~TextQuery() {
//}
//QueryResult::~QueryResult() {
//}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        throw runtime_error("参数错误!");
    }
    ifstream in(argv[1]);
    if (!in) {
        throw runtime_error("input file is no open!");
    }
    runQueries(in);
    return 0;
}



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容