1.本答案较于原文给的示例,主要在TextQuery的构造函数有所不同。
原文分解单词,如读到结尾,会将单词与“.”分解成一个单词,用下面处理,去掉分解的一段不带空格的字符串中的标点符号,获得单独的单词。
std::string word;
for (const auto &c : words)
{
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) // 非符号
{
word.push_back(c);
}
}
原文创建关联表时通过下表的方式,如果没有键,则自动添加,有键,则在值中添加行,由于值是一个set,元素不可重复,所以如果一行有多个相同的键,键所关联的set不会有相同的行,十分的巧妙的利用了map类下标插入和不可重复关联容器的性质,下段代码,不通过下表,而是先用find成员函数查询,如果遇到过则用insert插入行号,如果每遇到过则插入一个pair并插入对应行。
while (iss >> words) // 每行一个一个单词查询建表
{
std::string word;
for (const auto &c : words)
{
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) // 非符号
{
word.push_back(c);
}
}
auto it2 = WordLineNo.find(word);
if (it2 != WordLineNo.end())
{
it2->second->insert(ln); // 保存word存在当前行号的信息于set
}
else // word第一次遇到
{
std::shared_ptr<std::set<line_no>> NewSedLine(std::make_shared<std::set<line_no>>());
NewSedLine->insert(ln); // 保存word第一次出现的行号于其set
WordLineNo.insert({word, NewSedLine}); // map创建word对应键值对
}
}
2.本文读入的文件路径相对与可执行文件:"../used1.txt",起内容为从网上搜的一篇出师表英文翻译,链接为:百度安全验证
其内容如下:
The late emperor was taken from us before he could finish his life's work, the restoration of the Han. Today,
the empire is still divided in three, and our very survival is threatened. Yet still, the officials at court and the
soldiers throughout the realm remain loyal to you, your majesty. Because they remember the late emperor,
all of them, and they wish to repay his kindness in service to you. This is the moment to extend your divine
influence, to honor the memory of the late Emperor and strengthen the morale of your officers. It is not the
time to listen to bad advice or close your ears to the suggestions of loyal men.
The emperors of the Western Han chose their courtiers wisely, and their dynasty flourished. The emperors
of the Eastern Han chose poorly, and they doomed the empire to ruin. Whenever the late Emperor discussed
this problem with me, he lamented the failings of Emperors Huan and Ling.
I began as a common man, farming in my fields in Nanyang, doing what I could to survive in an age of chaos.
I never had any interest in making a name for myself as a noble. The late Emperor was not ashamed to visit my
cottage and seek my advice. Grateful for his regard, I responded to his appeal and threw myself into his service.
Now twenty-one years have passed.
The late Emperor always appreciated my caution and, in his final days, entrusted me with his cause. Since
that moment, I have been tormented day and night by the fear that I might let him down. That is why I crossed
the Lu river at the height of summer and entered the wastelands beyond. Now the south has been subdued,
and our forces are fully armed. I should lead our soldiers to conquer the northern heartland and attempt to
remove the hateful traitors, restore the house of Han, and return it to the former capital. This is the way I mean
to honor my debt to the late Emperor and fulfill my duty to you.
My only desire is to be permitted to drive out the traitors and restore the Han. If I let you down, punish my
offense and report it to the spirit of the late Emperor. Your Majesty, consider your course of action carefully.
Seeking out the good advice, and never forget the last words of the last Emperor. I depart now on a long expedition,
and I will be forever grateful if you heed my advice.Blinded by my own tears, I know not that I write.
3.完整的TextQuery.h文件内容
/**
****************************************************************************************
* @FilePath: TextQuery.h
* @Author: YMM
* @Date: 2024-04-21 20:23:39
* @LastEditors:
* @LastEditTime: 2024-04-21 20:28:51
* @Copyright: 2024 xxxTech CO.,LTD. All Rights Reserved.
* @Descripttion:
****************************************************************************************
*/
#ifndef _TEXTQUERY_
#define _TEXTQUERY_
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <algorithm>
class QueryResult
{
using line_no = std::vector<std::string>::size_type; // 行号数据类型
public:
QueryResult(const std::string &s,
std::shared_ptr<std::vector<std::string>> v,
std::shared_ptr<std::set<line_no>> ss)
: word(s), memText(v), WordLi(ss) {}
std::set<line_no>::iterator begin() { return WordLi->begin(); }
std::set<line_no>::iterator end() { return WordLi->end(); }
std::shared_ptr<std::vector<std::string>> get_file() { return memText; }
private:
const std::string word; // a要查询的单词
std::shared_ptr<std::vector<std::string>> memText; // 分行缓存文件内容对象
std::shared_ptr<std::set<line_no>> WordLi; // 要查询单词所在行号
friend std::ostream &printf(std::ostream &os, const QueryResult &q);
};
std::ostream &printf(std::ostream &os, const QueryResult &q)
{
os << q.word << " occurs " << q.WordLi->size() << [&]() -> std::string
{ return (q.WordLi->size() > 1) ? " times" : " time"; }() << std::endl; // 如果有多行则输出times;
for (const auto &it : *q.WordLi)
{
os << "\t(line " << it << ") " << (*q.memText)[it-1] << std::endl;
}
return os;
}
class TextQuery
{
using line_no = std::vector<std::string>::size_type; // 行号数据类型
public:
TextQuery(std::ifstream &infile);
QueryResult query(const std::string &wd);
private:
std::shared_ptr<std::vector<std::string>> memText; // 分行缓存文件内容对象
std::map<std::string, std::shared_ptr<std::set<line_no>>> WordLineNo; // 保存每个行号所对应的行号信息
};
TextQuery::TextQuery(std::ifstream &infile)
{
memText = std::make_shared<std::vector<std::string>>();
std::string stringLine;
line_no ln = 1; // 当前迭代所在行号
while (std::getline(infile, stringLine))
{
memText->push_back(stringLine); // 保存此行文件内容
std::istringstream iss(stringLine); // 初始化stringLine标准输入流iss
std::string words; // 分离的字符串
while (iss >> words) // 每行一个一个单词查询建表
{
std::string word;
for (const auto &c : words)
{
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) // 非符号
{
word.push_back(c);
}
}
auto it2 = WordLineNo.find(word);
if (it2 != WordLineNo.end())
{
it2->second->insert(ln); // 保存word存在当前行号的信息于set
}
else // word第一次遇到
{
std::shared_ptr<std::set<line_no>> NewSedLine(std::make_shared<std::set<line_no>>());
NewSedLine->insert(ln); // 保存word第一次出现的行号于其set
WordLineNo.insert({word, NewSedLine}); // map创建word对应键值对
}
}
++ln;
}
}
QueryResult TextQuery::query(const std::string &wd)
{
static std::shared_ptr<std::set<line_no>> nodate(new std::set<line_no>);
auto WordL = WordLineNo.find(wd); // 查询要查询单词关联的行号值
if (WordL == WordLineNo.end()) // 未查询要查询单词关联的行号值
{
return QueryResult(wd, memText, nodate);
}
else
return QueryResult(wd, memText, WordL->second);
}
#endif
4.main.c
/**
****************************************************************************************
* @FilePath: main.cpp
* @Author: YMM
* @Date: 2024-03-22 22:29:06
* @LastEditors: YMM
* @LastEditTime: 2024-03-28 13:01:40
* @Copyright: 2024 xxxTech CO.,LTD. All Rights Reserved.
* @Descripttion:
****************************************************************************************
*/
#include "../include/main.h"
using namespace std;
using namespace std::placeholders; // bind _
void runQueries(ifstream &infine)
{
TextQuery tq(infine);
while(true)
{
cout<<"enter word to look for,or q to quit: ";
string s;
if(!(cin>>s)||s == "q")break;
printf(cout,tq.query(s))<<endl;
}
}
int main()
{
#ifdef DEBUG
cout << "****************DEBUG BEGIN***************" << endl;
cout << "Source file path:" << __FILE__ << endl;
cout << "Compiling date:" << __DATE__ << endl;
cout << "Compile time:" << __TIME__ << endl;
#endif // DEBUG
ifstream ifs("../used1.txt");
runQueries(ifs);
return 0;
}
5.终端运行效果
ldl@ldl-virtual-machine:~/CppPrimer/bin$ ./main
enter word to look for,or q to quit: is
is occurs 6 times
(line 2) the empire is still divided in three, and our very survival is threatened. Yet still, the officials at court and the
(line 4) all of them, and they wish to repay his kindness in service to you. This is the moment to extend your divine
(line 5) influence, to honor the memory of the late Emperor and strengthen the morale of your officers. It is not the
(line 15) that moment, I have been tormented day and night by the fear that I might let him down. That is why I crossed
(line 18) remove the hateful traitors, restore the house of Han, and return it to the former capital. This is the way I mean
(line 20) My only desire is to be permitted to drive out the traitors and restore the Han. If I let you down, punish my
enter word to look for,or q to quit: bee
bee occurs 0 time
enter word to look for,or q to quit: tormented
tormented occurs 1 time
(line 15) that moment, I have been tormented day and night by the fear that I might let him down. That is why I crossed
enter word to look for,or q to quit: to
to occurs 13 times
(line 3) soldiers throughout the realm remain loyal to you, your majesty. Because they remember the late emperor,
(line 4) all of them, and they wish to repay his kindness in service to you. This is the moment to extend your divine
(line 5) influence, to honor the memory of the late Emperor and strengthen the morale of your officers. It is not the
(line 6) time to listen to bad advice or close your ears to the suggestions of loyal men.
(line 8) of the Eastern Han chose poorly, and they doomed the empire to ruin. Whenever the late Emperor discussed
(line 10) I began as a common man, farming in my fields in Nanyang, doing what I could to survive in an age of chaos.
(line 11) I never had any interest in making a name for myself as a noble. The late Emperor was not ashamed to visit my
(line 12) cottage and seek my advice. Grateful for his regard, I responded to his appeal and threw myself into his service.
(line 17) and our forces are fully armed. I should lead our soldiers to conquer the northern heartland and attempt to
(line 18) remove the hateful traitors, restore the house of Han, and return it to the former capital. This is the way I mean
(line 19) to honor my debt to the late Emperor and fulfill my duty to you.
(line 20) My only desire is to be permitted to drive out the traitors and restore the Han. If I let you down, punish my
(line 21) offense and report it to the spirit of the late Emperor. Your Majesty, consider your course of action carefully.
enter word to look for,or q to quit: q
ldl@ldl-virtual-machine:~/CppPrimer/bin$