cpp primer TextQuery练习

#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

// 因为一个查询类TextQuery需要一个接受一个ifstream
// 以及返回一个QueryResult表示string出现的那些行 表示行号和查询的文本
// 考虑使用vector<string>保存每行文件和一个保存单词行号的set
// 并且set行号与vector中的元素要一一对应。所以需要一个map来映射set和string
// 其中对于set是使用一个shared_ptr来管理
// 对于上面的两种数据类型我们使用 shared_ptr来进行管理

//为了定义函数query返回的类型这里的声明是十分必要的
class QueryResult;
class TextQuery {
 public:
  using line_no = std::vector<std::string>::size_type;
  //构造函数从文件流中读取并且建立行号和文本对应行的set
  TextQuery(std::ifstream &);

  // const成员函数用于返回一个带有行号和strig内容的QueryResult类型
  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(ifstream &is) : file(new vector<string>) {
  string text;
  while (getline(is, text)) {  //文件中的每一行
    file->push_back(text);     //加入到vector中保存当前行
    int n = file->size() - 1;  //当前的行号
    istringstream line(text);  //将当前行分解为单词
    string word;
    while (line >> word) {  //对于每个单词
      //如果单词不再wm中,以之为下标在wm中添加一项
      auto &lines = wm[word];  //这里的line是一个shared_ptr
      if (!lines) {            //第一次遇到这个单词 此指针为空
        lines.reset(new set<line_no>);  //分配一个新的set
      }
      //将这个行插入到set中 如果是重复的单词是无法插入到set里面的
      lines->insert(n);
    }
  }
}

// QueryResult类有三个数据成员
// 1. string用于保存查询的单词
// 2. 一个shared_ptr指向输入文件的vector(这样可以通过下标进行访问)
// 3. 一个shared_ptr指向保存单词出现的行号的set
// 唯一的成员函数是一个构造函数 初始化着三个数据成员
class QueryResult {
  //返回一个输出流
  friend std::ostream &print(std::ostream &, const QueryResult &);
  using line_no = std::vector<std::string>::size_type;

 public:
  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:
  std::string sought;                              //查询单词
  std::shared_ptr<std::set<line_no>> lines;        //出现的行号
  std::shared_ptr<std::vector<std::string>> file;  //输入文件
};

// query 函数
//接受一个string参数 即为查询单词
// const成员函数用于返回一个带有行号和strig内容的QueryResult类型
// QueryResult query(const std::string &) const;
QueryResult TextQuery::query(const string &sought) const {
  //如果没有找到sought 我们将返回一个指向此set的指针
  static shared_ptr<set<line_no>> nodata(new set<line_no>);
  //使用find而不是下标运算符来查找单词 避免将单词添加到wm中
  auto loc = wm.find(sought);
  if (loc == wm.end())
    return QueryResult(sought, nodata, file);  //没有找到
  else
    return QueryResult(sought, loc->second, file);  //返回一个临时拷贝
}

string make_plural(size_t ctr, const string &word, const string &ending) {
  return (ctr > 1) ? word + ending : word;
}

ostream &print(ostream &os, const QueryResult &qr) {
  //如果找到了单词 打印出现的次数和所有出现的位置
  os << qr.sought << " occurs " << qr.lines->size() << " "
     << make_plural(qr.lines->size(), "time", "s") << endl;
  //打印单词出现的每一行 遍历一个set
  for (auto num : *qr.lines) {  //对set中的每个单词
    //避免行号从0开始
    os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
  }
  return os;
}

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(int argc, char const *argv[]) {
  ifstream fs("C:\\Users\\oyx\\Desktop\\algorithm\\test.txt",std::ios::in);
  runQueries(fs);
  //system("pause");
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值