当前位置: 首页 > news >正文

【C++重载操作符与转换】文本查询示例

目录

一、文本查询系统的需求分析

二、核心数据结构设计

2.1 行号类型定义

2.2 单词查询结果类 QueryResult

2.3 文本查询类 TextQuery

三、文本查询类的实现

3.1 TextQuery 构造函数

3.2 query 函数

四、重载操作符与类型转换

4.1 重载 << 操作符

4.2 类型转换辅助(可选扩展)

五、完整代码示例 

六、功能扩展与优化

七、总结


在软件开发中,文本查询是一个常见的需求,比如搜索引擎、代码编辑器的查找功能等。C++ 提供了丰富的特性来实现高效的文本查询系统,其中重载操作符与类型转换的合理运用,能够让代码更加简洁、直观且易于维护。本文通过一个完整的文本查询示例,详细讲解如何利用 C++ 的重载操作符与转换功能,构建一个功能强大的文本查询工具,并深入剖析其中涉及的核心知识点。

一、文本查询系统的需求分析

一个基础的文本查询系统需要具备以下功能:

  1. 读取文本文件:将文件内容读取到程序中,作为查询的数据源。
  2. 单词索引:记录每个单词在文本中出现的位置(行号)。
  3. 查询功能:用户输入一个单词,系统返回该单词在文本中出现的所有位置及上下文信息。

为了实现这些功能,将借助 C++ 的标准库容器(如 vectormap),并通过重载操作符和类型转换,让代码的使用更加自然流畅。

二、核心数据结构设计

2.1 行号类型定义

首先,定义一个类型 line_no 表示文本中的行号,使用 using 进行类型重命名:

using line_no = std::vector<std::string>::size_type;

这里将 line_no 定义为 std::vector<std::string> 的大小类型,方便后续记录单词在文本中的行号位置。

2.2 单词查询结果类 QueryResult

QueryResult 类用于存储单个单词的查询结果,包括单词本身、包含该单词的文本以及单词出现的行号集合: 

class QueryResult {friend std::ostream& print(std::ostream&, const QueryResult&);std::string sought;  // 要查询的单词std::shared_ptr<std::vector<std::string>> file;  // 指向文本的指针std::shared_ptr<std::set<line_no>> lines;  // 单词出现的行号集合
public:QueryResult(const std::string& s, const std::shared_ptr<std::vector<std::string>>& f,const std::shared_ptr<std::set<line_no>>& l) : sought(s), file(f), lines(l) {}
};

使用智能指针 std::shared_ptr 管理 file 和 lines,确保内存的自动释放和共享。

2.3 文本查询类 TextQuery

TextQuery 类负责读取文本文件,并构建单词索引:

class TextQuery {
public:using line_no = std::vector<std::string>::size_type;TextQuery(std::ifstream&);QueryResult query(const std::string& sought) const;
private:std::shared_ptr<std::vector<std::string>> file;  // 存储文本内容std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;  // 单词到行号集合的映射
};

wm 是一个 map,键为单词,值为指向该行号集合的智能指针,用于快速查找单词出现的位置。

三、文本查询类的实现

3.1 TextQuery 构造函数

构造函数读取文本文件,并构建单词索引: 

TextQuery::TextQuery(std::ifstream& in) : file(std::make_shared<std::vector<std::string>>()) {std::string text;while (std::getline(in, text)) {file->push_back(text);  // 将每行文本存入 fileint n = file->size() - 1;  // 当前行号std::istringstream line(text);  // 将行文本拆分为单词std::string word;while (line >> word) {auto& lines = wm[word];  // 获取单词对应的行号集合if (!lines) {lines.reset(new std::set<line_no>);  // 首次出现,创建新集合}lines->insert(n);  // 记录单词出现的行号}}
}

通过 std::istringstream 将每行文本拆分为单词,并记录每个单词出现的行号。

3.2 query 函数

query 函数根据输入的单词,返回对应的查询结果: 

QueryResult TextQuery::query(const std::string& sought) const {static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);  // 未找到单词时的默认结果auto loc = wm.find(sought);if (loc == wm.end()) {return QueryResult(sought, file, nodata);  // 单词未找到} else {return QueryResult(sought, file, loc->second);  // 返回查询结果}
}

如果单词不存在,返回一个空的行号集合;否则返回该单词对应的行号集合。

四、重载操作符与类型转换

4.1 重载 << 操作符

为了方便输出查询结果,重载 << 操作符: 

std::ostream& print(std::ostream& os, const QueryResult& qr) {os << qr.sought << " occurs " << qr.lines->size() << " "<< (qr.lines->size() > 1? "times" : "time") << std::endl;for (line_no num : *qr.lines) {  // 输出单词出现的每一行os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << std::endl;}return os;
}

该操作符将查询结果以友好的格式输出,包括单词出现的次数和具体行内容。

4.2 类型转换辅助(可选扩展)

在某些场景下,可能需要将 QueryResult 转换为其他类型,比如转换为 JSON 格式用于网络传输。虽然在本示例中未涉及,但可以通过定义类型转换操作符实现: 

// 示例:将 QueryResult 转换为 JSON 字符串(假设存在 JsonString 类型)
operator JsonString() const {// 构建 JSON 字符串逻辑JsonString json;json.add("word", sought);json.add("occurrences", lines->size());// 添加行号和文本内容std::vector<JsonString> lineDetails;for (line_no num : *lines) {JsonString line;line.add("line_number", num + 1);line.add("text", *(file->begin() + num));lineDetails.push_back(line);}json.add("lines", lineDetails);return json;
}

通过定义 operator JsonString(),可以实现 QueryResult 到 JsonString 的隐式转换,方便在不同场景下使用查询结果。

五、完整代码示例 

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <set>
#include <map>using line_no = std::vector<std::string>::size_type;class QueryResult {friend std::ostream& print(std::ostream&, const QueryResult&);std::string sought;std::shared_ptr<std::vector<std::string>> file;std::shared_ptr<std::set<line_no>> lines;
public:QueryResult(const std::string& s, const std::shared_ptr<std::vector<std::string>>& f,const std::shared_ptr<std::set<line_no>>& l) : sought(s), file(f), lines(l) {}
};class TextQuery {
public:using line_no = std::vector<std::string>::size_type;TextQuery(std::ifstream&);QueryResult query(const std::string& sought) const;
private:std::shared_ptr<std::vector<std::string>> file;std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
};TextQuery::TextQuery(std::ifstream& in) : file(std::make_shared<std::vector<std::string>>()) {std::string text;while (std::getline(in, text)) {file->push_back(text);int n = file->size() - 1;std::istringstream line(text);std::string word;while (line >> word) {auto& lines = wm[word];if (!lines) {lines.reset(new std::set<line_no>);}lines->insert(n);}}
}QueryResult TextQuery::query(const std::string& sought) const {static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);auto loc = wm.find(sought);if (loc == wm.end()) {return QueryResult(sought, file, nodata);} else {return QueryResult(sought, file, loc->second);}
}std::ostream& print(std::ostream& os, const QueryResult& qr) {os << qr.sought << " occurs " << qr.lines->size() << " "<< (qr.lines->size() > 1? "times" : "time") << std::endl;for (line_no num : *qr.lines) {os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << std::endl;}return os;
}int main() {std::ifstream in("test.txt");  // 假设存在 test.txt 文件if (!in) {std::cerr << "Could not open file" << std::endl;return -1;}TextQuery tq(in);while (true) {std::cout << "enter word to look for, or q to quit: ";std::string s;if (!(std::cin >> s) || s == "q") break;print(std::cout, tq.query(s)) << std::endl;}return 0;
}

 

六、功能扩展与优化

①支持短语查询

通过修改 TextQuery 的索引构建逻辑,不仅记录单个单词的位置,还记录相邻单词组成的短语位置,从而支持短语查询。

②模糊查询

利用字符串匹配算法(如编辑距离算法),实现模糊查询功能,允许用户输入近似的单词进行查询。

③性能优化

  • 数据结构优化:使用更高效的数据结构,如 unordered_map 替换 map,提高单词索引的查询速度。
  • 缓存机制:添加查询结果缓存,避免重复查询相同单词时的重复计算。

七、总结

通过这个文本查询示例,我们深入了解了 C++ 中重载操作符与类型转换的实际应用。重载 << 操作符让查询结果的输出更加直观,而类型转换则为程序的扩展性提供了可能。同时,文本查询系统的实现过程也展示了如何合理运用标准库容器和智能指针,构建高效、安全的程序。在实际开发中,类似的思路可以应用于更多复杂场景,帮助开发者编写出简洁、强大的代码。

希望本文能帮助读者更好地掌握 C++ 的重载操作符与转换特性,并在实际项目中灵活运用。 


 

相关文章:

  • 数据库故障排查指南:解决常见问题,保障数据安全与稳定
  • 数据分析_Python
  • PyTorch实现三元组损失Triplet Loss
  • 为什么 Docker 建议关闭 Swap
  • 基于多头自注意力机制(MHSA)增强的YOLOv11主干网络—面向高精度目标检测的结构创新与性能优化
  • Elasticsearch Fetch阶段面试题
  • Springboot构建项目时lombok不生效
  • 51单片机仿真突然出问题
  • Almalinux中出现ens33 ethernet 未托管 -- lo loopback 未托管 --如何处理:
  • 提示词定制-AI写方案太泛?用“5W1H”提问法,细节拉满!
  • 售前工作.工作流程和工具
  • 【八股战神篇】Java集合高频面试题
  • nodejs快速入门到精通1
  • C++:C++内存管理
  • 题单:表达式求值1
  • 什么是差分传输?
  • 信任的进阶:LEI与vLEI协同推进跨境支付体系变革
  • 深入理解构造函数,析构函数
  • C语言内存管理:深入理解堆与栈
  • OpenResty 深度解析:构建高性能 Web 服务的终极方案
  • 山东茌平民企巨头实控人省外再出手:斥资16亿拿下山西一宗探矿权
  • 复旦建校120周年大型义诊举行,百余名专家服务市民超三千人次
  • 河南一女子被医院强制带走治疗,官方通报:当值医生停职
  • 女排奥运冠军宋妮娜:青少年保持身心健康才能走得更远
  • 泽连斯基:俄代表团级别低,没人能做决定
  • 中国进出口银行:1-4月投放制造业中长期贷款超1800亿元