这个玩意搞了三天 , 实现了俩个版本 , 一个是单文件 , 一个多文件合并的 ,其中多文件这个遇到很多bug ,搞了好久,总体来说这个程序帮助还是很大的, 对前面的章节合并了,实现的过程也不断的去翻前面的笔记。
结合智能指针 实现一个单词文本查询程序。

考虑到这两个类概念上“共享”了数据,可以使用shared_ptr。
开始一个程序的设计的一种好方法是列出程序的操作。了解需要哪些操作会帮助我们分析出需要什么样的数据结构。从需求入手,我们的文本查询程序需要完成如下任务:
· 当程序读取输入文件时,它必须记住单词出现的每一行。因此,程序需要逐行读取输入文件,并将每一行分解为独立的单词
· 当程序生成输出时:
— 它必须能提取每个单词所关联的行号
— 行号必须按升序出现且无重复
— 它必须能打印给定行号中的文本。

先看多文件版本 注释多 好理解一点
实现过程中遇到俩个BUG : 一个就是print 这个名字是标准库的名字, 报错根本找不到, 应该换一个。
另一个就是 头文件的定义, 声明了类,但是并没有声明它的构造函数,所以还是需要声明一下类的头文件!
main.cpp
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
#include "QueryResult.h"
#include "TextQuery.h"
using namespace std;
void runQueries(ifstream& infile) {
TextQuery tq(infile);
while (true) {
cout << "enter word or Q to quit ! : ";
string s;
//输入单词查询 or 输入Q 退出
if (cin >> s && (s != "q" && s != "Q")) myprint(cout, tq.query(s)) << endl;
else break;
}
}
int main() {
ifstream in("Text.txt");//打开文件
if (in.is_open()) { // 如果打开了
runQueries(in); // 查询
}
else {
cout << " open file error" << endl;
}
return 0;
}
QueryResult.h
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
using namespace std;
class QueryResult {
private:
string sought; // 查询的单词
shared_ptr<vector<string>> file; // 读入文件
shared_ptr<set<unsigned int>> lines; // 出现的行号
public:
friend ostream& myprint(ostream&, const QueryResult&); //不能用书上的print 不然运行不了
//QueryRestlt(){}
QueryResult(string s, shared_ptr<set<unsigned int>> p, shared_ptr<vector<string>> f)
: sought(s), file(f), lines(p) { } // 构造
};
TextQuery.h
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
//#include "QueryResult.h"
using namespace std;
class QueryResult;
class TextQuery {
private:
shared_ptr<vector<string>> file; // 用于接收传入的文件 的每一行字符串
map<string, shared_ptr<set<unsigned int>>> wm; // 每个单词映射到对应的行号
public:
// TextQuery(){ };
TextQuery(ifstream& infile); // 构造函数
QueryResult query(const string&); // 查询
};
TextQuery.cpp
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
#include "QueryResult.h" // 还是需要声明头文件
#include "TextQuery.h"//里面只声明类 但是没有构造函数
using namespace std;
class QueryResult;
TextQuery::TextQuery(ifstream& infile) : file(new vector<string>) {
string tmp;
while (getline(infile, tmp)) { //读入文件 的每一行
file->push_back(tmp); // 存入 vs
int lineNo = (int)file->size() - 1; // 当前行号
istringstream line(tmp); // 转化为 is
string word;
while (line >> word) { // is ——》 每个单词
shared_ptr<set<unsigned int>>& lines = wm[word]; // 注意这是个指针,要new开辟空间
if (!lines) // 如果这个单词没有的话 为空 需要开辟空间
lines.reset(new set<unsigned int>); //分配一个新的set
else
lines->insert(lineNo); // 向set中插入行号
}
}
}
QueryResult TextQuery::query(const string& s) { //查询单词
static shared_ptr<set<unsigned int>> nodata(new set<unsigned int>);
auto loc = wm.find(s);
if (loc == wm.end()) { // 如果没有找到
return QueryResult(s, nodata, file);
}
else { // 如果找到了
return QueryResult(s, loc->second, file);
}
}
QueryResult.cpp
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
#include "QueryResult.h"
using namespace std;
ostream& myprint(ostream& out, const QueryResult& qr) { // 第一个是参数IO 第二个参数 查询的QueryResult对象
out << qr.sought << " occurs " << qr.lines->size() << ' ' << "times"
<< endl;
for (auto num : *(qr.lines)) { // 遍历输出 如果没有这个单词 解引用为空
out << "\t(line" << num + 1 << ") " << *(qr.file->begin() + num) << endl; // 打印行号和
}
return out;
}
单文件就不需要考虑那么多了, 只需要把函数整合一起
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<memory>
#include<map>
#include<set>
using namespace std;
class QueryResult{
private:
string sought;
shared_ptr<vector<string>> file;
shared_ptr<set<unsigned int>> lines;
public:
friend ostream& print(ostream& out,const QueryResult& qr);
QueryResult(string s,shared_ptr<set<unsigned int>> p,shared_ptr<vector<string>> f)
: sought(s),file(f),lines(p) { }
};
ostream& print(ostream& out,const QueryResult& qr){
out << qr.sought << " occurs " << qr.lines->size() << ' ' << "times"
<< endl;
for(auto num : *(qr.lines)){
out<<"\t(line"<< num+1 <<") " << *(qr.file->begin()+num) <<endl;
}
return out;
}
class TextQuery{
private:
shared_ptr<vector<string>> file;
map<string,shared_ptr<set<unsigned int>>> wm;
public:
TextQuery(){ }
TextQuery(ifstream &infile): file(new vector<string>)
{
string tmp;
while(getline(infile,tmp)){
file->push_back(tmp);
int lineNo = file->size()-1; // 当前行号
istringstream line(tmp);
string word;
while(line>>word){
shared_ptr<set<unsigned int>> &lines = wm[word]; // 注意这是个指针,要new开辟空间
if(!lines) // 看set中是否已经有了
lines.reset(new set<unsigned int>);
lines->insert(lineNo); // 向set中插入行号
}
}
}
QueryResult query(const string &s){
static shared_ptr<set<unsigned int>> nodata(new set<unsigned int>);
auto loc = wm.find(s);
if(loc == wm.end()){
return QueryResult(s,nodata,file);
}
else {
return QueryResult(s,loc->second,file);
}
}
};
void runQueries(ifstream &infile)
{
TextQuery tq(infile);
while (true)
{
cout<<"enter word or Q to quit ! : ";
string s;
if(cin>>s && (s!="q" && s!="Q")) print(cout, tq.query(s)) <<endl;
else break;
}
}
int main()
{
string fileName = "Text.txt";
ifstream in(fileName);
if(in.is_open()){
runQueries(in);
}
else cout<< " open file error" <<endl;
return 0;
}
Text.txt 内容可以自己加

