#RAG|NLP|Jieba|PDF2WORD# pdf转word-换行问题

文档在生成PDF时,文宁都发生了什么。本文讲解了配置对象、resources对象和content对象的作用,以及字体、宇号、坐标、文本摆放等过程。同时,还解释了为什么PDF转word或转文字都是一行一行的以及为什么页眉页脚的问题会加大识别难度。最后提到了文本的编码和PDF中缺少文档结构标记的问题。PDF转word更像是一种逆向工程。

第三方库pdf转word的痛点-格式不保留

本文着力解决换行问题:

  1. 源文本正常输入,pdf解析第三方库识别出来多余换行符

    原文:“你好”
    识别:“你\n好”
  2. 源文本出现多个换行符,pdf解析第三方库识别出一个换行符

    原文:“你好\n\n\n\n\n\n我是向日葵花子”
    识别:“你好\n我是向日葵花子”

word 转 pdf 经历了什么

文本转换为PDF时,记录的信息

包括:

  1. 位置和大小信息:记录每个文本在页面上的位置和大小。
  2. 字体信息:记录文本所使用的字体名称、大小和样式。
  3. 颜色信息:记录文本的颜色。
  4. 行间距和段落间距:记录文本之间的行间距和段落之间的间距。
  5. 文本属性:记录文本的对齐方式、装饰等其他属性。
  6. 超链接和书签:记录文本中的超链接和书签信息,以实现交互功能。
    这些信息的记录旨在确保在PDF中正确呈现文本内容,并保持文档的原始格式和布局。

pdf文本信息

pdf文本是由文本空间组成的,其中包含:
文本矩阵,定义下一个字形的当前转换。它由文本定位和显示运算符的文本改变。
文本行矩阵,它是当前行开头的文本矩阵的状态。因此,通过使用操作员移动到下一行,可以垂直对齐文本行,而无需手动跟踪行的开始位置。
这些矩阵不会从文本部分持续到文本部分,而是在每个文本部分的开头重置为单位矩阵。 结合字体大小,水平缩放和文本上升,这两个矩阵定义了从文本空间到用户空间的转换。

如何获得pdf信息

大段处理

可以在调用第三方库的过程中加一些小算法,我这里给一点点提示

  1. 读取pdf基本信息
  2. 逐行获取pdf信息
  3. 根据每行的行宽来判断是不是多输出了换行符
  4. 每行即使没有文字只有换行符也要加入到获取的信息中
    这一步可以完成百分之八十的换行格式还原。

获取每行信息的代码:

    with pdfplumber.open(file_path) as pdf:for p in pdf.pages:# print(p.bbox)page_lines = p.extract_text_lines()

接下来就要去分析文档每行的信息,然后利用坐标去处理了,大家可以自己思考下代码怎么写。
在这里插入图片描述

页眉页脚、大小标题

识别处理思路和大段处理一致

小段处理

在这里插入图片描述

通过坐标处理不了两行的小段,特别是开头没有缩进的unstructured文本,这里我们需要加上其他算法。
我使用的是nlp的文本分析进行兜底。
处理流程:

  1. 分析上下文关系优化结构算法: 在获取到文本内容后,可以编写一个分析句子上下文关系的算法来处理文本,对于出现问题的地方进行修正。
    主要用到:
    词性标注(Part-of-Speech Tagging): 词性标注是将句子中的每个词汇标记为其对应的词性(如名词、动词、形容词等)的过程。通过词性标注可以识别句子中各个词汇的语法角色,从而帮助理解句子的结构和含义。
    句法分析(Syntax Parsing): 句法分析是分析句子中各个词汇之间的语法关系,如主谓关系、动宾关系等。通过句法分析可以构建句子的语法树,从而帮助理解句子的结构和语义。
  2. 合并文本: 根据分析结果,将需要合并的部分合并到一起。
  3. 输出结果:输出处理后的文本。
    这一步可以完成到90%的换行格式还原,通过不断优化句法分析的规则,可以逐渐接近100%。

清洗文本

nlp句法分析是分析句子中各个词汇之间的语法关系,因此,像emoji或者其他特殊、对于计算机语义处理无意义的符号保留下来必定对结果产生很大影响,最终合并的效果大打折扣,所以我们需要先对文本进行一个清洗,去掉无意义的符号。
由于我的文档只涉及到emoji这种特殊符号,所以我只进行了emoji的清洗

def remove_emoji(text):emoji_pattern = re.compile("["u"\U0001F600-\U0001F64F"  # emoticonsu"\U0001F300-\U0001F5FF"  # symbols & pictographsu"\U0001F680-\U0001F6FF"  # transport & map symbolsu"\U0001F1E0-\U0001F1FF"  # flags (iOS)u"\U00002600-\U000027BF"  # miscellaneous symbolsu"\U0001F300-\U0001FAD6"  # additional emoticons"]+", flags=re.UNICODE)return emoji_pattern.sub(r'', text)

句子拆分

按照逗号拆分就可以,然后找到带有换行符号的句子进行进一步的词性标注
注意只取带有换行符的小句,这样可以提高工作效率减少无意义的算法调用

使用split函数即可

词性标注

在这里插入图片描述

为了分析句子语法关系、上下文关系,我们必须先进行词性标注,构建语法树,然后再进行句子分析
这里我直接用的中文nlp库jieba,其他好用的库可以直接替换使用,如果是英文词性标注可以使用ntlk,ntlk也有中文词性标注,但是我中文标注我更喜欢用jieba
jieba的jieba词性标注表我也给大家整理好了
词性标注的代码:

import jieba.posseg as psg
# 分词和词性标注
seg = psg.cut(sentence)
# 定义语法规则
result_list = []
verbs = []
for word, pos in seg:# 对句法树进行处理,这里只是简单打印出来,你可以根据需要处理print("句法树:", word, pos)word_info = {'word': word, 'pos': pos}# 将字典添加到列表中result_list.append(word_info)if pos == 'v':verbs.append(word_info)
verbs = [word for word, pos in seg if pos == 'v']

分析上下文关系

词性标注结束后,我们就可以根据语法树分析上下文关系了

merged_sentences = []
for i, sentence in enumerate(sentences):if i > 0:# 分析上下文关系verbs_prev, seg_prev = analyze_context(sentences[i - 1])verbs_curr, seg_curr = analyze_context(sentence)x = list(seg_prev)# 如果前一个句子或当前句子至少有一个含有动词,则进行合并if (len(verbs_prev) == 1 and len(verbs_curr) == 0) or (len(verbs_prev) == 0 and len(verbs_curr) == 1):merged_sentences[-1] += sentence# 如果上一句的最后一个词和下一句的第一个词都是动词,则进行合并elif seg_prev[-1] and seg_curr[0] and seg_prev[-1]["pos"] in ['r', 'v'] and seg_curr[0]["pos"] == 'v':merged_sentences[-1] += sentence# 代词和指示词:如果后一个句子以代词或指示词开头,这可能表明它是对前一个句子的补充。elif seg_curr[0]["pos"] in ['r', 'z', 'c'] or seg_curr[0]["word"] in ['这', '那', '其', ...]:merged_sentences[-1] += sentence# 时间+nelif seg_curr[0]["pos"] in ['n'] or seg_prev[0]["pos"] in ['t', 'm', ...]:merged_sentences[-1] += sentence# 句号和分号:虽然句号和分号通常表示句子的结束,但如果它们后面紧跟的是小写字母或标点符号,可能意味着这是同一句话的一部分。elif seg_prev[-1]["word"] in ['。', ';'] and not seg_curr[0]["word"].istitle():merged_sentences[-1] += sentence# 如果后一个句子的第一个词是“的”并且前一个句子的最后一个词是动词,则进行合并elif seg_curr[0] and seg_curr[0]["pos"] == 'm' and seg_prev[-1] and seg_prev[-1]["pos"] == 'v':merged_sentences[-1] += sentences[i]# 如果后一个句子的第一个词是“的”并且前一个句子的最后一个词是动词,则进行合并elif seg_curr[0] and seg_curr[0]["pos"] == 'p' and seg_prev[-1] and seg_prev[-1]["pos"] == 'd':merged_sentences[-1] += sentences[i]# 3. 如果上一句的最后一个词是标点符号,且下一句的第一个词不是句首发语词,则进行合并elif seg_prev[-1]["pos"] == 'x' and seg_curr[0]["pos"] not in ['c', 'r', 'u', 'p', 'm', 'e']:merged_sentences[-1] += sentence# 4. 如果上一句的最后一个词是名词或动词,且下一句以时间状语或条件状语开头,则进行合并elif (seg_prev[-1]["pos"] in {'n', 'vg', 'v'}) and (seg_curr[0]["pos"] in {'f', 'c'}):merged_sentences[-1] += sentenceelse:merged_sentences.append(sentence)else:merged_sentences.append(sentence)

我在判断规则的同时,进行了是否合并的判断,这样 我们就得到了合并后的文本merged_sentences
在这里插入图片描述

参考文献

https://www.bilibili.com/video/BV1Vi4y1C71M/?spm_id_from=333.788&vd_source=8c9777cd5733f7f447f766cd5105041b

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

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

相关文章

hbuiderx+uniapp基于Android宠物饲养交流养宠系统 微信小程序3_reqva

3.2 APP需求分析 作为一款宠物饲养管理APP,面向的是大多数学者,软件的界面设计简洁清晰,用户可轻松掌握使用技巧。在调查之后,获得用户以下需求: (1)用户注册登录后,可进入系统解锁更…

Oracle 集群】RAC知识图文详细教程(四)--缓存融合技术和主要后台进程

Cache Fusion 原理 前面已经介绍了 RAC 的后台进程,为了更深入的了解这些后台进程的工作原理,先了解一下 RAC 中多节点对共享数据文件访问的管理是如何进行的。要了解 RAC 工作原理的中心,需要知道 Cache Fusion 这个重要的概念,要…

C#使用RabbitMQ-4_路由模式(直连交换机)

简介 RabbitMQ中的路由模式是一种根据Routing Key有条件地将消息筛选后发送给消费者的模式。在路由模式中,生产者向交换机发送消息时,会指定一个Routing Key。交换机接收生产者的消息后,根据消息的Routing Key将其路由到与Routing Key完全匹…

Win10 专业版WSL2 如何安装Ubuntu22.04

环境: Win10 专业版 19041 WSL2 Ubuntu22.04 问题描述: Win10 专业版WSL2 如何安装Ubuntu22.04 解决方案: 1.启用 WSL 相关功能: 打开cmd终端(管理员权限) 运行以下命令以启用虚拟机平台功能&#…

linux环境安装git、maven、jenkins等

重启 jenkins的命令: systemctl start jenkins 如果没有vim 命令 可以使用 yum install vim 安装 vim git 下载包地址 https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz 1.安装依赖环境: yum install -y curl-devel expat-devel ge…

CTFshow-pwn入门-栈溢出 (慢慢更

文章目录 pwn 35pwn 36pwn 37pwn 38pwn 39pwn 40 好几天没发博客了,忙着吃席去了 QAQ pwn 35 Partial RELRD,NX 开启 char dest;声明一个名为dest的字符变量。return strcpy(&dest, src);使用strcpy函数将src字符串复制到dest字符数组中,并返回指向…

【Vue】2-8、Axios 网络请求

cdn&#xff1a;<script src"https://unpkg.com/axios/dist/axios.min.js"></script> 注&#xff1a;使用 CDN 链接就可以不需要去下载对应的 js 文件到本地&#xff0c;只需要联网即可使用&#xff0c;可以减少项目的体积 <!DOCTYPE html> <…

【51单片机系列】中断优先级介绍及使用

文章来源&#xff1a;《51单片机原理及应用&#xff08;第3版&#xff09;》5.4节。 51单片机采用了自然优先级和人工设置高、低优先级的策略。 当CPU处理低优先级中断&#xff0c;又发生更高级中断时&#xff0c;此时中断处理过程如下图所示。 一个正在执行的低优先级中断服…

刷存在感,Excel转Protobuf/Json通用配置文件

使用场景 最近工作流中有将Excel转Protobuf作为配置文件的技术方案。具体实现是先定一个proto文件&#xff0c;再在一个对应excel表中定义对应字段&#xff0c;由策划在excel进行更改。proto文件可以生成对应语言的脚本&#xff0c;然后将excel转成对应protobuf的binary。 我…

Leetcode第382场周赛

Leetcode第382场周赛 本人水平有限&#xff0c;只做前三道。 一、按键变更的次数 给你一个下标从 0 开始的字符串 s &#xff0c;该字符串由用户输入。按键变更的定义是&#xff1a;使用与上次使用的按键不同的键。例如 s “ab” 表示按键变更一次&#xff0c;而 s “bBBb”…

Codeforces Round 922 (Div. 2 ABCDEF题)

A. Brick Wall Problem Statement A brick is a strip of size 1 k 1 \times k 1k, placed horizontally or vertically, where k k k can be an arbitrary number that is at least 2 2 2 ( k ≥ 2 k \ge 2 k≥2). A brick wall of size n m n \times m nm is such a…

Pandas进阶--map映射,分组聚合和透视pivot_table详解

文章目录 1.Pandas的map映射&#xff08;1&#xff09;映射&#xff08;2&#xff09;map充当运算工具 2.数据分组和透视&#xff08;1&#xff09;分组统计 - groupby功能 是pandas最重要的功能&#xff08;2&#xff09;聚合agg 3.透视表pivot_table&#xff08;1&#xff09…

小程序上的h5页面在web上面访问 页面基于vue

前提&#xff1a;BASE_URL: https://ded.toll.keeke.ai/ded-api/ 页面路径是&#xff1a;pages/webview/webview 参数是&#xff1a;id111 列表页跳转到详情页的方法是 toDetail(e) {wx.navigateTo({url: ../webview/webview?id e.currentTarget.dataset.oid})}, vue的映射…

【日常问题】Failed to enable unit: Unit file docker.service does not exist.

Failed to enable unit: Unit file docker.service does not exist. 1. 问题原因 笔者问题的产生是因为在ubuntu20.04下采用snapd安装的docker&#xff0c;因此 systemctl restart docker.servicesystemd并不能找到守护进程docker.service 同时使用docker命令时还会产生若干…

React Router 完美教程(上)

概述 什么叫路由呢&#xff0c;说白了就是如何处理页面的跳转。在传统的网站中&#xff0c;我们都是向服务器请求页面及相应的css和js代码。自从前后端分离的相思提出后&#xff0c;一堆基于js虚拟Dom的框架应运而生。React就是其中优秀的代表作之一。这种方式极大的优化了开发…

Conventional SortSearch

Merge Sort——from bottom to top(iteration) void merge_sort( ElementType list[], ElementType sorted[], int N, int length ){int size1;for(;size<N;size*2){for(int i0;i<N;i2*size){int l1i; int l2sizei;int locl1;while(l1<isize&&l1<N&…

etcd自动化安装配置教程

文章目录 前言一、简介1. 简介2. 特点3. 端口介绍 二、etcd安装教程&#xff08;单机版&#xff09;1. 复制脚本2. 增加执行权限3. 执行脚本4. 查看启动状态5. 卸载etcd 三、etcd安装教程&#xff08;集群版&#xff09;1. 复制脚本2. 增加执行权限3. 分发脚本4. 执行脚本5. 启…

中科大计网学习记录笔记(一):Internet | 网络边缘

计算机网络 前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面…

【JavaSE篇】——内部类

目录 &#x1f393;内部类 &#x1f388;内部类的分类 &#x1f6a9;实例内部类 一.如何实例内部类对象 二.实例内部类中为什么不能有静态成员变量 &#xff08;用final解决&#xff09; 三.在实例内部类对象时&#xff0c;如何访问外部类当中相同的成员变量&#xff1f;…

SpringMVC-基本概念

一、引子 我们在上篇文章Spring集成Web中抛出了一个问题&#xff1a;为什么我们一直在自用Java Web阶段使用的Servlet来承接客户端浏览器的请求呢&#xff0c;我们熟知甚至是已经在日常开发中经常使用的Controller又与之有什么关系呢&#xff1f;我们将在本篇文章解答读者的这…