C++文本查询程序(智能指针)
文本查询程序
在一个指定的文件中查询单词,查询结果是单词在文章中总共出现的次数,以及在所在行的列表,如果一个单词在一行出现多次,则只记录一次,行会按照升序输出。
打印示例:
文本查询程序设计
- 使用**vector< string >**存储整个读入文件的拷贝,每行保存为vector的一个元素,利用vector的下标操作来访问每一行。
- 使用istringstream来拆解每一行变为单词。
- 使用set保存每个单词在输入文本中出现的行号。保证了每行只出现了一次且行号按升序保存。
- 使用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; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209732.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)