【Boost】:parser代码的基本结构(二)

parser代码的基本结构

  • 一.总体概述
  • 二. EumeFile的实现
  • 三.ParserHtml的实现
  • 四.SaveHtml实现
  • 五.完整源代码

打开parser.cc,用vscode或者vim都行。

一.总体概述

在这里插入图片描述

首先递归式的把文件名和路径读入一个数组内,接着把数组内的每一个数据按照一定的格式进行划分,最后把划分后的内容输入到output路径里。

在这里插入图片描述

二. EumeFile的实现

由于C++库对于文件的实现并不完整,所以我们需要使用Boost库里的函数。

安装Boost开发库

在这里插入图片描述

需要注意的是,我们现在做的是Boost库的搜索引擎,并非对它的源代码进行搜索,而是对它的使用手册进行搜索。

首先判断该路径是否存在,接着以递归的方式不断搜索文件,再判断搜索到的是否是普通文件,然后再是否是以.html结尾,最后将它的路径存入。

在这里插入图片描述

测试一下

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试完成,没有问题。

三.ParserHtml的实现

该函数主要功能:读取信息,然后分离出title,content,url。

总体框架

在这里插入图片描述

1.读取文件

由于读文件是非常常用的,所以我们将它封装在一个工具类里

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.解析title

title的查找很简单,找到两个title之间的部分就行了。

在这里插入图片描述

3.获取content

此处我们使用一个小技巧,定义两种状态:标签和内容。遍历整个文件,当遇到<时变为标签状态,此时不读取;当遇到>时,变为内容状态,此时开始读取。

在这里插入图片描述

4.获取URL

boost库的官方文档是与我们下载后的html有路径对应关系。

官网链接:

在这里插入图片描述

我们下载的链接:

在这里插入图片描述

data/input/accumulators.html

所以,本质是把下载下来的boost库 doc/html拷贝到了data/input下。实际上我们要对我们当前获取的路径进行剪切和拼接,将data/input/accumulators.html变成https://www.boost.org/doc/libs/1_84_0/doc/html/accumulators.html。这样就能得到官网的URL了。

在这里插入图片描述

测试:由于数据很多,我们看一个就行了

在这里插入图片描述

在这里插入图片描述

测试完毕,没有问题。

四.SaveHtml实现

为了方便我们使用getline能一次读出来整个文件,对于文档内部使用\3分割,文档之间使用\n分割。例如:title\3content\3url\n 。

在这里插入图片描述

在这里插入图片描述

测试

在这里插入图片描述

测试完成,没问题。

五.完整源代码

parse.cc

#include <iostream>
#include <vector>
#include <string>
#include <boost/filesystem.hpp>
#include "util.hpp"const std::string src_path = "data/input/";         // 要读取的文件路径
const std::string output = "data/raw_html/raw.txt"; // 存放处理后文件路径typedef struct DocInfo
{std::string title;   // 文档标题std::string content; // 文档内容std::string url;     // 文档路径
} DocInfo_t;// const &:表示输入
//&:输入输出
//*:输出
bool EnumFile(const std::string &src_path, std::vector<std::string> *files_lists);
bool ParseHtml(const std::vector<std::string> &files_lists, std::vector<DocInfo_t> *results);
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output);int main()
{// 第一步:读取目标文件的路径和文件名std::vector<std::string> files_lists;if (!EnumFile(src_path, &files_lists)){std::cerr << "enum file error" << std::endl;return 1;}// 第二步:把读取的文件按照格式进行解析std::vector<DocInfo_t> results;if (!ParseHtml(files_lists, &results)){std::cerr << "parse html error" << std::endl;return 2;}// 第三步:把解析后的文件输出到output路径里if (!SaveHtml(results, output)){std::cerr << "save html error" << std::endl;return 3;}return 0;
}bool EnumFile(const std::string &src_path, std::vector<std::string> *files_lists)
{// 定义一个path对象,从当前路径开始查找boost::filesystem::path root_path(src_path);if (!boost::filesystem::exists(root_path)) // 如果当前路径不存在就返回false{std::cerr << src_path << "not exists" << std::endl;return false;}// 定义一个空的迭代器,判断是否结束boost::filesystem::recursive_directory_iterator end;// 开始递归搜索for (boost::filesystem::recursive_directory_iterator iter(root_path); iter != end; iter++){// 如果不是普通文件,跳过if (!boost::filesystem::is_regular_file(*iter)){continue;}// 如果不是以html结尾,跳过if (iter->path().extension() != ".html"){continue;}// 测试代码,之后删除// std::cout<<"debug"<<iter->path().string()<<std::endl;// 将满足条件的网页的路径存入files_lists->push_back(iter->path().string());}return true;
}static bool ParaseTitle(const std::string &file, std::string *title)
{std::size_t begin = file.find("<title>");if (begin == std::string::npos)return false;begin += 7;std::size_t end = file.find("</title>");if (end == std::string::npos)return false;if (begin > end)return false;*title = file.substr(begin, end - begin);return true;
}static bool ParseContent(const std::string &file, std::string *content)
{// 一个简易的状态机enum state{LABEL,CONTENT};// 初始化为LABELenum state s = LABEL;for (char c : file){switch (s){case LABEL:if (c == '>')s = CONTENT;break;case CONTENT:if (c == '<')s = LABEL;else{// 我们不想要原始文档里的换行符,因为我们想用\n作为之后文档分隔符if (c == '\n')c = ' ';content->push_back(c);}break;default:break;}}return true;
}static bool ParseUrl(const std::string &file, std::string *url)
{std::string head = "https://www.boost.org/doc/libs/1_84_0/doc/html/";std::string tail = file.substr(src_path.size());*url = head + tail;return true;
}bool ParseHtml(const std::vector<std::string> &files_lists, std::vector<DocInfo_t> *results)
{for (const std::string &file : files_lists){// 1.读取文件std::string result;if (!ns_util::FillUtil::ReadFile(file, &result)){continue;}DocInfo_t doc;// 提取titleif (!ParaseTitle(result, &doc.title)){continue;}// 提取contentif (!ParseContent(result, &doc.content)){continue;}// 提取URLif (!ParseUrl(file, &doc.url)){continue;}// 放入结果results->push_back(std::move(doc));//细节;因为直接使用push_back会发生拷贝,为了提高效率使用move// 测试代码//  std::cout<<"title:"<<doc.title<<std::endl;//  std::cout<<"content:"<<doc.content<<std::endl;//  std::cout<<"url:"<<doc.url<<std::endl;//  break;}return true;
}
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output)
{// 创建输出对象std::ofstream out(output);if (!out.is_open()){std::cerr << "open:" << output << "failed!" << std::endl;return false;}// 将其格式化for (auto &item : results){std::string result;result += item.title;result += '\3';result += item.content;result += '\3';result += item.url;result += '\n';out.write(result.c_str(), result.size());}out.close();return true;
}

util.hpp

#include<iostream>
#include<string>
#include<fstream>namespace ns_util
{class FillUtil{public:static bool ReadFile(const std::string &file_path,std::string *out){std::ifstream in(file_path);//创建对象,这种创建模式,默认打开文件//判断文件是否打开if(!in.is_open()){std::cerr<<"open file"<<file_path<<"error"<<std::endl;return false;}//读取文件,按行读取std::string line;while(std::getline(in,line))//getline的返回值是istream类型,但该类内部进行了重载,所以可以直接判断{*out+=line;}//关闭文件in.close();return true;}};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创建型模式-单例模式:定义、实现及应用

目录 一、模式定义二、针对问题1.解决的问题2.解决方案3.举个例子4.设计模式适合场景5.实现方式6.优缺点7.与其他模式的关系 三、代码实现 一、模式定义 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型模式&#xff0c;用于限制某个类只能创建一个对象。它提…

大数据信用报告查询费用一般要多少钱?

一些不少朋友在申贷的时候被拒贷之后&#xff0c;得到的原因就是因为大数据不良被拒&#xff0c;这时候很多人都反过来查询自己的大数据信用报告&#xff0c;而查询的价格也是不少朋友都比较关注的&#xff0c;那大数据信用报告查询费用一般要多少钱呢?下面本文就为你介绍一下…

vue3中如何实现图片的压缩

首先&#xff0c;为什么需要进行图片压缩&#xff1a; 减少页面加载时间&#xff1a;因为图片是页面中常见的资源之一&#xff0c;较大的图片会增加页面的加载时间&#xff0c;影响用户体验&#xff0c;压缩图片可以减小图片的文件大小&#xff0c;提升页面加载速度。节省网络…

App ICP备案获取iOS和Android的公钥和证书指纹

依照《工业和信息化部关于开展移动互联网应用程序备案工作的通知》&#xff0c;向iOS和安卓平台提交App时需要先提交ICP备案信息。 iOS平台&#xff1a; 1、下载appuploader工具&#xff1a;Appuploader home -- A tool improve ios develop efficiency such as submit ipa to…

vue yarn certificate has expired

背景&#xff1a;我在用ant design pro框架进行初始化时&#xff0c;安装脚手架时&#xff0c;安装yarn时显示报错 原因分析&#xff1a;查了很久的资料&#xff0c;这种情况应该是开了服务器代理访问导致ssl安全证书失效了 解决办法&#xff1a; 在终端输入&#xff1a;yarn…

【MybatisPlus篇】查询条件设置(范围匹配 | 模糊匹配 | 空判定 | 包含性判定 | 分组 | 排序)

文章目录 &#x1f384;环境准备⭐导入依赖⭐写入User类⭐配置启动类⭐创建UserDao 的 MyBatis Mapper 接口&#xff0c;用于定义数据库访问操作⭐创建配置文件&#x1f6f8;创建测试类MpATest.java &#x1f354;范围查询⭐eq⭐between⭐gt &#x1f354;模糊匹配⭐like &…

使用ngrok内网穿透

没有服务器和公网IP&#xff0c;想要其他人访问自己做好的网站&#xff0c;使用这款简单免费的内网穿透小工具——ngrok&#xff0c;有了它轻松让别人访问你的项目~ 一、下载ngrok 官网地址&#xff1a;ngrok | Unified Application Delivery Platform for Developers&#x…

Redis(十一)单线程VS多线程

文章目录 概述为何选择单线程主要性能瓶颈多线程特性和IO多路复用概述Unix网络编程中的五种IO模型Blocking IO-阻塞IONoneBlocking IO-非阻塞IOIO multiplexing-IO多路复用signal driven IO-信号驱动IOasynchronous IO-异步IO 场景&#xff1a;引出epoll总结 开启Redis多线程其…

ADB的配置和使用及刷机root

ADB的配置和使用 ADB即Android Debug Bridge&#xff0c;安卓调试桥&#xff0c;是谷歌为安卓开发者提供的开发工具之一&#xff0c;可以让你的电脑以指令窗口的方式控制手机。可以在安卓开发者网页中的 SDK 平台工具页面下直接下载对应系统的 adb 配置文件&#xff0c;大小只…

Apache Doris 整合 FLINK CDC + Iceberg 构建实时湖仓一体的联邦查询

1概况 本文展示如何使用 Flink CDC Iceberg Doris 构建实时湖仓一体的联邦查询分析&#xff0c;Doris 1.1版本提供了Iceberg的支持&#xff0c;本文主要展示Doris和Iceberg怎么使用&#xff0c;大家按照步骤可以一步步完成。完整体验整个搭建操作的过程。 2系统架构 我们整…

Vue打包Webpack源码及物理路径泄漏问题解决

修复前&#xff1a; 找到vue.config.js文件&#xff0c;在其中增加配置 module.exports {productionSourceMap: false,// webpack 配置configureWebpack: {devtool: false,}}其中打包的物理路径泄露我这边试了好多次&#xff0c;发现只有打包的时候NODE_ENVproduction 才能保…

Vue中的计算属性和侦听器(监视器)

一、computed计算属性 1.概念 基于现有的数据&#xff0c;计算出来的新属性。 依赖的数据变化&#xff0c;自动重新计算。 2.语法 声明在 computed 配置项中&#xff0c;一个计算属性对应一个函数 使用起来和普通属性一样使用 {{ 计算属性名}} 3.注意 computed配置项和da…

【网络】 WireShark实现TCP三次握手和四次挥手

目录 一、WireShark介绍 二、什么是TCP 三、TCP三次握手 四、TCP四次挥手 一、WireShark介绍 WireShark是一个开源的网络分析工具&#xff0c;用于捕获和分析网络数据包。它可以在多个操作系统上运行&#xff0c;包括Windows、Mac OS和Linux。 使用WireShark&#xff0c;…

Faster-Whisper 实时识别电脑语音转文本

Faster-Whisper 实时识别电脑语音转文本 前言项目搭建环境安装Faster-Whisper下载模型编写测试代码运行测试代码实时转写脚本 参考 前言 以前做的智能对话软件接的Baidu API&#xff0c;想换成本地的&#xff0c;就搭一套Faster-Whisper吧。 下面是B站视频实时转写的截图 项…

版本管理git及其命令介绍-附带详细操作

前言 在版本管理时代之前&#xff0c;人们写软件的方式如下图1所示 图1 无版本管理的代码 其坏处就是软件版本随着时间越来越多&#xff0c;每个版本修改了什么内容&#xff0c;修改了哪些文件&#xff0c;如果没有详细记录也不知道。这样久会导致如果我们想回退到某个版本内…

MCU方案选型和进口替代,点击查看~

一、MCU简介 MCU&#xff08;微控制单元&#xff09;俗称单片机&#xff0c;可被认为是CPU的缩减版本&#xff0c;把CPU的频率与规格进行缩减处理&#xff0c;并将RAM、ROM、时钟、A/D转换、定时/计数器、UART 、DMA等电路单元&#xff0c;甚至包括USB接口、LCD驱动电路都整合…

缓存框架jetcache

在实际应用中&#xff0c;并不是单一的使用本地缓存或者redis&#xff0c;更多是组合使用来满足不同的业务场景。 jetcache组件实现了优雅的组合本地缓存和远程缓存。 支持多种缓存类型&#xff1a;本地缓存、分布式缓存、多级缓存。 官网地址&#xff1a;https://github.com…

《向量数据库指南》——Milvus Cloud丝滑入库是影响开发体验的第一步

除了查询之外,“插入”应该是使用最多的一个数据库操作,所有后续的工作也是建立在数据成功插入的基础上。丝滑的入库体验,是影响开发体验的第一步,也是至关重要的一步。 Milvus Cloud 社区对于“插入”的讨论,主要集中在数据插入的实践经验上: “插入的速度怎么优…

各版本的Qt Creator的下载地址

2024年2月3日&#xff0c;周六上午 Index of /official_releases/qtcreatorhttps://download.qt.io/official_releases/qtcreator/ 如果想下载测试中的最新版Qt Creator的快照可以去这个地址 Index of /snapshots/qtcreatorhttps://download.qt.io/snapshots/qtcreator/

浅谈智慧消防在铁路系统中的应用与发展

摘要&#xff1a;文章从基于物联网技术的“智慧消防”概念入手&#xff0c;探讨了智慧消防物联网技术在铁路工程中的应用&#xff0c;分析了在实际应用过程中存在的部分难点&#xff0c;并提出了新型物联网无线组网、智能传感器技术、图形可视化技术及安全隐患预测与评估的技术…