【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
  };
  // 初始化为LABEL
  enum 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;
    // 提取title
    if (!ParaseTitle(result, &doc.title))
    {
      continue;
    }
    // 提取content
    if (!ParseContent(result, &doc.content))
    {
      continue;
    }

    // 提取URL
    if (!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;
    }
  };
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云原生业务全流程DevOps配置预研与实践

背景 我在一个二线城市&#xff08;山东济南&#xff09;&#xff0c;相对与北上广深杭这些IT业发达的城市来说&#xff0c;济南IT业对于业内新技术的接受度是有点慢的&#xff0c;国内很多一线大厂早先几年前就开始实践使用的技术&#xff0c;我们这边也是近两年才开始慢慢兴…

10. BI - 决策树的使用及可视化

本文为 「茶桁的 AI 秘籍 - BI 篇 第 10 篇」 文章目录 可视化探索决策树原理决策树算法决策树可视化泰坦尼克海难数据 Hi&#xff0c;你好。我是茶桁。 上一节课&#xff0c;咱们了解了图形的具体绘制方法&#xff0c;接下来咱们还要看看除了图形绘制之外&#xff0c;还有哪些…

手把手教你开发Python桌面应用-PyQt6图书管理系统-主界面UI背景及状态栏代码设置

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…

山东淄博刑侦大队利用无人机抓获盗窃团伙

山东淄博刑侦大队利用无人机抓获盗窃团伙 近期&#xff0c;山东淄博临淄区发生多起盗窃案件。通过视频追踪和调查访问&#xff0c;推断临淄区某村可能为嫌疑人藏匿地点。刑侦大队无人机应急小组迅速到达现场&#xff0c;经无人机高空侦查&#xff0c;发现并锁定了嫌疑人的藏匿…

5. 基础网络服务与应用配置

5.1 实验一&#xff1a;FTP 基础配置实验 5.1.1 实验介绍 5.1.1.1 关于本实验 设备支持多种文件管理方式&#xff0c;用户根据任务和安全性要求选择合适的文件管理方式。 用户可以通过直接登录系统、FTP&#xff08;File Transfer Protocol&#xff09;、TFTP&#xff08;T…

Linux实验记录:使用vsftpd服务传输文件

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 备注&#xff1a; 为了解决在多样复杂的设备之间解决传…

2024年数学建模美赛 A~E 题目解析

2024美赛A题&#xff1a;资源可用性和性别比例 背景 尽管一些动物物种不属于通常的雄性或雌性&#xff0c;大多数物种在出生时要么显著地为雄性&#xff0c;要么为雌性。虽然许多物种在出生时表现出1:1的性别比&#xff0c;但其他物种则偏离了这个均衡的性别比例。这被称为性…

Netty核心原理与基础实战(二)——详解Bootstrap 备份

接上篇&#xff1a;Netty核心原理与基础实战&#xff08;一&#xff09; 1 Bootstrap基础概念 Bootstrap类是Netty提供的一个便利的工厂类&#xff0c;可以通过它来完成Netty的客户端或服务端的Netty组件的组装&#xff0c;以及Netty程序的初始化和启动执行。Netty的官方解释是…

【Linux】线程池

线程池 一、线程池的概念1、线程池的优点2、线程池的应用场景 二、线程池的实现1、实现逻辑2、threadpool线程池&#xff08;1&#xff09;threadpool.hpp代码&#xff08;2&#xff09;为什么线程池中需要有互斥锁和条件变量&#xff1f;&#xff08;3&#xff09;注意点&…

elk之简介

写在前面 本文看下es的简介。 1&#xff1a;简介 背后公司&#xff0c;elastic&#xff0c;08年纽交所上市&#xff0c;与腾讯&#xff0c;阿里等云厂商有合作&#xff0c;推出云产品&#xff0c;类似功能的产品由solr&#xff0c;splunk&#xff0c;但使用量es当前遥遥领先…

[pytorch入门] 9. 优化器

介绍 在pytorch的官方文档中&#xff0c;所有的优化器都集中在torch.optim中 在官方文档中&#xff0c;会告诉你如何去创建一个优化器 选择一种优化器创建&#xff0c;传入模型的参数&#xff08;必需的&#xff09;、学习速率&#xff08;几乎是每个优化器都有的参数&#…

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏9(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言回收物品素材绘制UI代码控制垃圾桶回收功能效果 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中&#xff0c;我们将…

DPVS 多活部署架构部署

一、目标 利用DPVS部署一个基于OSPF/ECMP的提供HTTP服务的多活高可用的测试环境。 本次部署仅用于验证功能&#xff0c;不提供性能验证。 配置两台DPVS组成集群、两台REAL SERVER提供实际HTTP服务。 注&#xff1a;在虚拟环境里面&#xff0c;通过在一台虚拟服务器上面安装FR…

2024牛客寒假算法基础集训营1

文章目录 A DFS搜索M牛客老粉才知道的秘密G why外卖E 本题又主要考察了贪心B 关鸡C 按闹分配 今天的牛客&#xff0c;说是都是基础题&#xff0c;头昏昏的&#xff0c;感觉真不会写&#xff0c;只能赛后补题了 A DFS搜索 写的时候刚开始以为还是比较难的&#xff0c;和dfs有关…

老版本labelme如何不保存imagedata

我的版本是3.16&#xff0c;默认英文且不带取消保存imagedata的选项。 最简单粗暴的方法就是在json文件保存时把传递过来的imagedata数据设定为None&#xff0c;方法如下&#xff1a; 找到labelme的源文件&#xff0c;例如&#xff1a;D:\conda\envs\deeplab\Lib\site-packages…

数据分析基础之《pandas(4)—pandas画图》

1、DataFrame.plot(xNone, yNone, kindline) 说明&#xff1a; x&#xff1a;设置x轴标签 y&#xff1a;设置y轴标签 kind&#xff1a; line 折线图 bar 柱状图 hist 直方图 pie 饼图 scatter 散点图 # 找到p_change和turnover之间的关系 data.plot(xvolume, yturnover, kinds…

dubbo+sentinel最简集成实例

说明 在集成seata后&#xff0c;下面来集成sentinel进行服务链路追踪管理&#xff5e; 背景 sample-front网关服务已配置好 集成 一、启动sentinel.jar 1、官网下载 选择1:在本地启动 nohup java -Dserver.port8082 -Dcsp.sentinel.dashboard.serverlocalhost:8082 -Dp…

Simulink|光伏阵列模拟多类故障(开路/短路/阴影遮挡/老化)

目录 主要内容 模型研究 1.正常模型 2.断路故障 3.短路故障 4.阴影遮挡 5.老化模型 结果一览 1.U-I曲线 2.P-V曲线 下载链接 主要内容 该模型为光伏阵列模拟故障情况simulink模型&#xff0c;程序实现了多种故障方式下的光伏阵列输出功率-电压-电流关系特…

链表——C语言——day17

链表 链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。在用数组存放数据时&#xff0c;必须事先定义固定的长度&#xff08;即元素个数&#xff09;。链表则没有这种缺点&#xff0c;它根据需要开辟内存单元。 链表有一个“头指针“变量&#xff0c;图中…

Docker极速入门掌握基本概念和用法

1、Docker概念 1.1什么是docker Docker是一个快速交付应用、运行应用的技术&#xff0c;具备以下优势 可将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通…