C++文本查询程序(智能指针)

文本查询程序

在一个指定的文件中查询单词,查询结果是单词在文章中总共出现的次数,以及在所在行的列表,如果一个单词在一行出现多次,则只记录一次,行会按照升序输出。

打印示例:
在这里插入图片描述

文本查询程序设计

  1. 使用**vector< string >**存储整个读入文件的拷贝,每行保存为vector的一个元素,利用vector的下标操作来访问每一行。
  2. 使用istringstream来拆解每一行变为单词。
  3. 使用set保存每个单词在输入文本中出现的行号。保证了每行只出现了一次且行号按升序保存。
  4. 使用map来将每个单词与它所出现的行号set关联起来。

数据结构:

  • 使用vector存储文件内容
  • map关键字为要查询的单词,值为set<size_t> ,表示所在的行号。
vector<string> file; //读取文件
map<string,set<size_t>>; //关键字:值 = 单词:出现的行号

【代码】:不使用类的版本

string file_name;
cout << "输入文件名:";
cin >> file_name;
ifstream in_file(file_name);
if (!in_file.is_open())
{
cerr << "文件打开失败!\n";
exit(-1);
}
vector<string> vec;
map<string, set<size_t>> MAP;
string text_str;
while (getline(in_file,text_str)) //读取每一行,存储在vector的每一个元素
{
vec.push_back(text_str);
}
for (size_t i = 0; i < vec.size(); ++i)
{
cout << vec[i] << endl;
}
string research;
string word;
while ([&]()->bool{ cout << "请输入你要查询的单词(输入quit退出): "; return (cin >> research && research != "quit"); }())
{
for (size_t i = 0; i < vec.size(); ++i)
{
istringstream line_str(vec[i]); //读取每一行
while (line_str >> word)
{
if (research == word)
{
MAP[word].insert(i); // 单词:行号
break;
}
}
}
//注意此处MAP里面存储了要查询的单词,其值为对应的行号,遍历行号,根据行号打印出对应在vector里的行内容
cout << "element occurs " << MAP[research].size() << " times" << endl;
for (auto it = MAP[research].cbegin(); it != MAP[research].cend(); ++it)
{
cout << '\t' << "(line " << *it << ") " << vec[*it] << endl;
}
}

【代码】:使用类(在类之间共享数据)

我们需要在TextQuery类中读取数据,在TextResult类中打印数据
我们不妨利用shared_ptr来共享数据:(关于shared_ptr及其他智能指针,请看:我写的动态分配与智能指针博文

  • 将TextQuery中读取的文件内容的vector作为shared_ptr来共享到TextResult中,方便打印时遍历文件。
  • 将TextQuery中读取的map集合的set作为shared_ptr来共享到TextResult中,这样就可以直接获得单词在的行号,根据shared_ptr中vector共享的内容,就可以直接读文件内容。
  • 在TextResult的一个构造函数中可以直接共享数据。

读取内容的类:

shared_ptr<vector<string>> file; //拷贝文件内容
map<string, shared_ptr<set<line_NO>>> wm; //每个单词和它所出现的行号

共享到 打印内容的类:

string research; //查询的单词
shared_ptr <set<line_NO>> lines; //出现的行号,set集合
shared_ptr <vector<string>> file; //输入文件,vector容器




完整代码及测试:

using line_NO = vector<string>::size_type;
class QueryResult; //前向声明
class TextQuery //读取类
{
public:
//读取指定输入的构造函数
TextQuery(ifstream& i_file);
//查询操作
QueryResult query(const string& word)const; //函数作用是:将读入的数据传给打印的类。
private:
shared_ptr<vector<string>> file; //拷贝文件内容
map<string, shared_ptr<set<line_NO>>> wm; //每个单词和它所出现的行号
};
class QueryResult //打印类
{
friend ostream& print(ostream& os, const QueryResult& q); //作为类的友元函数
public:
QueryResult(string s, shared_ptr<set<line_NO>> p, shared_ptr<vector<string>> f)
:research(s), lines(p), file(f) {} //接受来自读取的类的数据
private:
string research; //查询单词
shared_ptr <set<line_NO>> lines; //出现的行号,set集合
shared_ptr <vector<string>> file; //输入文件,vector容器
};
TextQuery::TextQuery(ifstream& i_file) :file(new vector<string>)
{
string text;
while (getline(i_file, text))
{
file->push_back(text); //文件每一行存入vector
auto No = file->size() - 1;
istringstream line(text); //读取这一行
string word;
while (line >> word)
{
//读取行的每个单词
auto& lines = wm[word];//lines是一个shared_ptr
if (!lines)
{
lines.reset(new set<line_NO>); //分配一个新的set
}
lines->insert(No); //将此行号插入到set中
}
}
}
QueryResult TextQuery::query(const string& word) const
{
//未找到查询单词,定义一个空的set,
static shared_ptr<set<line_NO>> nodata(new set<line_NO>);
auto loc = wm.find(word); //查找关键字
if (loc == wm.end()) //返回一个指向这个关键字对应的所有的值的map迭代器
{
return QueryResult(word, nodata, file); //将空set传入,表示未找到
}
else
{
return QueryResult(word, loc->second, file); //传入关键字对应的set集合
}
}
ostream& print(ostream& os, const QueryResult& q)
{
//找到了单词,打印出现次数和所出现的位置
//set的size成员函数返回set关键字的个数
os << q.research << " occurs " << q.lines->size() << endl;
for (auto num : *q.lines) //得到在set中对应的行号
{
//在文件中根据获得的行号来打印
os << "\t(line " << num + 1 << ") " << *(q.file->begin() + num) << endl;
}
return os;
}
int main()
{
ifstream in_file("111.txt");
TextQuery tq(in_file);
while (true)
{
cout << "请输入要查询的单词,输入quit退出: ";
string word;
if (!(cin >> word) || word== "quit")
{
break;
}
print(cout, tq.query(word)) << endl;
}
return 0;
}

在这里插入图片描述

posted @   hugeYlh  阅读(25)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示