《C++ primer》文本查询程序一

这是《C++ primer》中的一个示例程序,看了几遍仍觉有些细节没有明白,故手敲了一遍

需了解STL容器部分知识点,智能指针,文件流,string流

《C++ primer》文本查询程序一

书上给的例子尚有瑕疵,如果单词在同一行出现多次,则只会记录为一次,本人能力有限,尚未解决此问题

以下是写完程序后绘制的思维导图

image-20240413155500846

代码部分

  • main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<iostream>
#include<fstream>
#include"TextQuery.h"
#include"ResultQuery.h"
using namespace std;

void runQueries(ifstream& fin);

int main(void)
{
string filename;
cout << "请输入你要查询的文件名(包含后缀)"<<endl;
cin >> filename;
ifstream readFile(filename, ios::in);
if (readFile.is_open())
{
runQueries(readFile);
}
else
cout << "the file open failed!!!" << endl;
}

void runQueries(ifstream& fin)
{
TextQuery tq(fin);
while (1)
{
cout << "please enter word to look for, or q to quit." << endl;
string needle;
if (cin >> needle && needle != "q" && needle != "Q")
{
MyPrint(cout, tq.query(needle)) << endl;
}
else break;
}
}
  • TextQuery.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma once
#include<memory>
#include<string>
#include<map>
#include<set>
#include<vector>
#include"ResultQuery.h"

using namespace std;

class TextQuery {
private:
shared_ptr<vector<string>> file; //智能指针 多个对象共享数据 存储地址
map<string, shared_ptr<set<int>>> wm; //间接实现单词与行号之间的映射
public:
TextQuery(ifstream& fin); //构造函数
ResultQuery query(string needle); //用来整理出目标单词的相关信息,然后传递给ResultQuery
};

  • TextQuery.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "TextQuery.h"
#include<string>
#include<sstream>
#include<fstream>
using namespace std;
TextQuery::TextQuery(ifstream& fin):file(new vector<string>)
{
string lineContent;
size_t lineNo;
while(getline(fin,lineContent)) // 将文件内容拆分为一行一行
{
file->push_back(lineContent);
lineNo = file->size() - 1; //从零开始计数,方便之后利用迭代器进行输出查询结果
istringstream line(lineContent); //利用string流 将一行内容再拆分为每个单词
string word;
while (line >> word) //实现每个单词与对应行号之间的映射
{
shared_ptr<set<int>>& NO = wm[word]; // 在map中如果使用下标未找到对应的值,则会自动生成一个默认值
if (!NO)
{
NO.reset(new set<int>); //清空默认值,使其是一个指向set<int>型的指针
NO->insert(lineNo); //将这个单词所在的行号拷贝给 指针指向的那个空间
}
else
NO->insert(lineNo);
}
}
}

ResultQuery TextQuery::query(string needle)
{
shared_ptr<set<int>> nothing (new set<int>);
auto result = wm.find(needle);
if (result == wm.end())
{
return ResultQuery(needle,file, nothing);
}
else
{
return ResultQuery(needle,file, result->second);
}
}

  • ResultQuery.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
#include<memory>
#include<string>
#include<vector>
#include<set>
#include<map>
using namespace std;
class ResultQuery
{
private:
string needle;
shared_ptr<vector<string>> file;
shared_ptr<set<int>> lines;
public:
ResultQuery(string n, shared_ptr<vector<string>> f, shared_ptr<set<int>> l) :\
needle(n), file(f), lines(l) {} //构造函数 进行初始化
friend ostream& MyPrint(ostream&, const ResultQuery&);
};


  • ResultQuery.cpp

1
2
3
4
5
6
7
8
9
10
#include "ResultQuery.h"
#include <iostream>
ostream& MyPrint(ostream& os, const ResultQuery& rq) {
os<< rq.needle << " occurs " << rq.lines->size() << "times in the file " << endl;
for (auto line : *(rq.lines))
{
os << "\tline:"<<line+1<< " "<<rq.file->begin()[line]<<endl;
}
return os;
}