定义你自己版本的 TextQuery 和 QueryResult 类,并执行12.3.1(P431)中的 runQueries 的函数。
文件包含:main.cpp textquery.h textquery.cpp queryresult.h file.dat(待查询文本)
// main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "textquery.h"
#include "queryresult.h"
void runQueries(std::ifstream &infile);
int main(int argc, char *argv[]) {
if (argc == 2) {
std::ifstream infile(argv[1]);
runQueries(infile);
} else {
std::cerr << "Usage: query myfile" << std::endl;
std::exit(EXIT_FAILURE);
}
}
void runQueries(std::ifstream &infile) {
TextQuery tq(infile);
while (true) {
std::cout << "enter word to look for, or q to quit: ";
std::string s;
if (!(std::cin >> s) || s == "q")
break;
print(std::cout, tq.query(s)) << std::endl;
}
}
//辅助函数 生成词尾复数
std::string make_plural(std::size_t ctr, const std::string &word,
const std::string &ending) {
return (ctr > 1) ? word + ending : word;
}
std::ostream &print(std::ostream &os, const QueryResult &qr) { // queryresult 友元函数
//找到单词,打印出现次数及所有出现行号
os << qr.sought << " occurs " << qr.lines->size() << " "
<< make_plural(qr.lines->size(), "time", "s") << std::endl;
//打印单词出现的每行
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ")" //行号为容器索引从0开始
<< *(qr.file->begin() + num) << std::endl;
return os;
}
// textquery.h
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <vector>
#include <string>
#include <memory>
#include <map>
#include <set>
#include "queryresult.h"
class QueryResult;
class TextQuery {
public:
using line_no = std::vector<std::string>::size_type;
TextQuery(std::ifstream&);
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; //单词到行号集合的映射
};
#endif
// textquery.cpp
#include "textquery.h"
#include <fstream>
#include <sstream>
TextQuery::TextQuery(std::ifstream& is)
: file(new std::vector<std::string>) {
std::string text;
while (std::getline(is, text)) { //读取文件每行
file->push_back(text); //保存此行文体
int n = file->size() - 1; //当前行号
std::istringstream line(text);
std::string word;
while (line >> word) {
auto & lines = wm[word]; //lines为shared_ptr<set<line_no>>对象引用
if (!lines) //首次遇到单词并分配set空间
lines.reset(new std::set<line_no>); //shared_ptr<>托管set new分配空间
lines->insert(n); //set记录行号
}
}
}
QueryResult TextQuery::query(const std::string& sought) const {
//未找到sought返回指向此setr的指针 默认初始化值为空
static std::shared_ptr<std::set<line_no>> nodata(new std::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); //找到
}
// queryresult.h
#ifndef QUERYRESULT_H
#define QUERYRESULT_H
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <set>
class QueryResult {
public:
using line_no = std::vector<std::string>::size_type;
friend std::ostream& print(std::ostream&, const QueryResult&);
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; //输入文件
};
#endif
命令行输入并编译:
g++ main.cpp textquery.h textquery.cpp queryresult.h -o query
使用:
./query file.dat