Parser 模块:HTML 分析与数据洗濯

[复制链接]
发表于 2025-10-18 14:16:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前言:

在构建 boost 库站内搜刮引擎时,Parser 模块是数据处置惩罚的焦点环节,它的焦点功能包罗:

  • 筛选出全部 .html 文件,为后续分析提供数据源;
  • 从 .html 文件中提取 title、content ,并构造对应官网的 url 所在;
  • 将洗濯后的数据按自界说格式存储为文本文件,便于后续创建索引。
本文重要解说编写 Parser 模块过程中涉及的部分知识。
1. EnumFile() 方法

EnumFile() 方法的功能是,递归遍历指定目次及其子目次,网络全部后缀为 .html 的平凡文件路径,并将结果存储到传入的 std::vector<std::string> 中。
1.1 boost::filesystem 简介

boost::filesystem 是 Boost 库中的一个组件,用于跨平台处置惩罚文件体系路径、文件使用和目次管理。它提供了面向对象的接口,简化了文件和目次的创建、删除、遍历等使用。
使用:

  • 包罗头文件:#include <boost/filesystem>
  • 链接 Boost 库:-lboost_system -lboost_filesystem
1.2 焦点类及其使用

1.2.1 path

boost::filesystem::path 用于体现文件体系路径(如文件或目次的路径),提供了跨平台的路径使用本事。
在 Windows 平台,D:\Develop\条记\Boost库搜刮引擎开辟 可以被正确分析。
在 Linux 平台,/home/ZhengTongren/boost-search/data/input 可以被正确分析。
path 可以通过 std::string、const char* 或别的 path 对象举行构造。
  1. const std::string src_path = "data/input/";
  2. boost::filesystem::path root_path(src_path);
复制代码
干系方法:

  • filesystem::exists(path) :查抄路径是否存在
  • is_regular_file(path) :判断是否为平凡文件
  • path.extension() :获取拓展名,带 . ,如 .html
1.2.2 recursive_directory_iterator

recursive  adj. 递归的
boost::filesystem 中,directory_iterator 和 recursive_directory_iterator 的作用雷同于一个 “指针”,用于遍历文件体系中的目次内容。
directory_iterator 提供了一种方式来迭代一个指定目次的内容,但它不会递归进入子目次。
recursive_directory_iterator 则提供了递归遍历目次的功能,它不光会列出指定目次下的全部条目,还会进入每个子目次继续遍历,直到遍历完备个目次树。
  1. boost::filesystem::recursive_directory_iterator it(root_path);
  2. // root_path 是一个 filesystem::path 类对象;
  3. // 创建一个递归迭代器,指向 root_path 目录中的第一个条目(文件或子目录);
  4. // 如果 root_path 不存在或无法访问,则抛出 filesystem_error 异常
  5. boost::filesystem::recursive_directory_iterator end;
  6. // 默认构造的迭代器表示结束
  7. for (; it != end; ++it) { }
  8. // 通过循环逐个访问条目,直到等于 end
复制代码
1.3 递归遍历、搜集全部 .html 文件路径
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <boost/filesystem>
  5. const std::string src_path = "data/input/";
  6. bool EnumFile(const std::string& src_path, std::vector<std::string>* files_list)
  7. {
  8.     namespace fs = boost::filesystem;
  9.     // 1. 初始化 path
  10.     fs::path root_path(src_path);
  11.     // 2. 检查路径是否存在 -- 不存在则 return false
  12.     if (!fs::exists(root_path))
  13.     {
  14.         std::cerr << src_path << " not exits!" << std::endl;
  15.         return false;
  16.     }
  17.     // 3. 递归遍历目录及其子目录文件
  18.     fs::recursive_directory_iterator end;
  19.     for (fs::recursive_directory_iterator it(root_path); it != end; ++it)
  20.     {
  21.         // 3.1 跳过目录文件
  22.         if (!is_regular_file(*it)) continue;
  23.         // 3.2 跳过非 .html 普通文件
  24.         if (it->path().extension() != ".html") continue;
  25.         // 3.3 插入
  26.         files_list->push_back(it->path().c_str());
  27.     }
  28.     return true;
  29. }
复制代码
2. 文件流使用与 getline

2.1 C++ 文件流类

C++ 中的文件流使用通过 <fstream> 头文件提供的类(如 ifstream、ofstream、fstream)实现,支持对文件的读写使用。
ifstream 用于从文件中读取数据;ofstream 用于将数据写入文件;fstream 支持同时读写文件。
打开模式:

  • std::ios::in :以输入模式打开文件
  • std::ios:ut :以输出模式打开文件(覆盖模式)
  • std::ios::app :以追加模式打开文件
  • std::ios::binary :以二进制模式打开文件
文件的读写模式必须保持划一,以默认模式写入则以默认模式读取,以二进制模式写入则以二进制模式读取。
对于二进制文件,数据直接按其原始字节序列被读取或写入,没有任何表明或转换,这对于处置惩罚图像、音频、视频等非文本数据尤为告急。
  1. // 通用写入函数(二进制)
  2. bool WriteFile(const std::string& path, const std::string& content)
  3. {
  4.     std::ofstream out(path, std::ios::out | std::ios::binary);
  5.     if (!out.is_open()) return false;
  6.    
  7.     out << content;
  8.     return true;
  9. }
  10. // 通用读取函数(二进制)
  11. bool ReadFile(const std::string& path, std::string* out)
  12. {
  13.     std::ifstream in(path, std::ios::in | std::ios::binary);
  14.     if (!in.is_open()) return false;
  15.    
  16.     std::string line;
  17.     while (getline(in, line))
  18.     {
  19.         // ...
  20.     }
  21.     return true;
  22. }
复制代码
C++ 的文件流类(如 ifstream、ofstream)依照 RAII 原则:

  • 资源与对象生命周期绑定:文件流对象在构造时打开文件,在析构时自动调用 close() ;
  • 无需手动干预:当流对象离开作用域(即生命周期竣事),析构函数会确保文件正确关闭。
因此,通例环境下可以不显式调用 close() 方法。
在长时间运行的步伐中,若须要提前关闭不再使用的文件、立即开释资源,可以显式调用 close() 。
2.2 getline 函数

getline 函数用于从输入流中按行读取字符串,它会读取直到遇到换行符 \n 为止,并将此换行符从输入流中提取掉(但 \n 不会包罗在返回的字符串中)。
常见用法:

  • 从 std::cin 中读取一行
  1. std::string line;
  2. getline(std::cin, line);
复制代码

  • 从文件流中逐行读取
  1. std::ifstream in(path, std::ios::in);
  2. if (!in.is_open()) return ;
  3. std::string line;
  4. while (getline(in, line))
  5. {
  6.     // ...
  7. }
  8. in.close();
复制代码

  • getline() 支持自界说分隔符
  1. istream& getline (istream& is, string& str);
  2. istream& getline (istream& is, string& str, char delim); // 通过 getline 的第三个参数 delim
  3. char delimiter = ',';
  4. std::string line;
  5. getline(std::cin, line, delimiter);
复制代码
2.3 使用 getline vs stringstream

getline 逐行读取,得当处置惩罚大文件,或须要对每一行举行特定处置惩罚的环境。
stringstream 一次性读取整个文件到内存中,得当小文件处置惩罚场景;对于较大的文件,这种方法大概导致内存溢出。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表