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

news2024/11/15 9:50:54

文档在生成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"  # emoticons
                               u"\U0001F300-\U0001F5FF"  # symbols & pictographs
                               u"\U0001F680-\U0001F6FF"  # transport & map symbols
                               u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
                               u"\U00002600-\U000027BF"  # miscellaneous symbols
                               u"\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
        # 时间+n
        elif 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] += sentence
        else:
            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.coloradmin.cn/o/1424163.html

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

相关文章

7zip压缩包乱码问题

打开压缩包查看或解压时,发现其中的文件名显示乱码。 经网络搜索,判断是编码的问题。因为我OS是UTF-8,而压缩包编码是CP936。 解决方法只能用命令行,-mcp指定了code page: "c:\Program Files\7-Zip\7z.exe&quo…

阿里云智能集团副总裁安筱鹏:企业数字化的终局是什么?

以下文章来源于数字化企业 ,作者安筱鹏博士 回答数字化终局追问的起点是,企业需要重新定义我是谁。成为有竞争力的行业领导厂商,你应当成为一个客户运营商,即能够实时洞察、实时满足客户需求,追求极致的客户体验。而要…

12.scala下划线使用总结

目录 概述实践变量初始化导包引入方法转变为函数用户访问Tuple元素简化函数参数传递定义偏函数变长参数 结束 概述 实践 变量初始化 在Scala中,变量在声明时需要显式指定初始值。可以使用下划线为变量提供初始值,但这种语法仅限于成员变量,…

抠门精出游记第三天

熊野古道,最早我是在新加坡地铁站看到的日本旅游广告上出现的,我觉得以前很多次自由行都是打卡式的,觉得确实需要一些深度游,而且趁着身体状态还可以,反正就这么种草了。 然后小红书上看到不少有关行程介绍&#xff0c…

npm i 遇到了 npm ERR! code CERT_HAS_EXPIRED

npm i 遇到了 npm ERR! code CERT_HAS_EXPIRED 更新你的系统时间【命令 date】。确保你的计算机上的时间和时区设置正确,并且与当前时间相符。 清除你的 npm 缓存。使用 npm cache clean --force 命令清除你的 npm 缓存,关闭ssl验证,并重新运…

使用 Docker 部署超级马里奥 Web 游戏

一、游戏介绍 超级马里奥 是一款经典闯关游戏,也叫做超级玛丽。由红白机 FC 游戏移植而来,简约的游戏画面,加上简单的操作方式,让你重温儿时的经典。 二、环境检查 1)检查操作系统版本 检查本次实践的操作系统版本 ca…

使用VScode远程连接Ubuntu

君衍. 一、环境准备二、配置VScode三、远程连接Ubuntu 平常远程连接服务器的工具有很多,比如Moba、Xshell、putty、甚至CRT都可以进行远程连接服务器,但是他们的本质是相同的,都是使用ssh来进行远程连接。 这里我们之所以要使用VScode远程连接…

Debezium发布历史100

原文地址: https://debezium.io/blog/2020/12/17/debezium-1-4-cr1-released/ 欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯. Debezium 1.4.0.CR1 发布 2020 年 12 月 17 日 作者: 克里斯…

SpringCloud Gateway(4.1.0) 返回503:原因分析与解决方案

文章目录 一、环境版本二、原因分析三、解决方案 一、环境版本 Versionspring-cloud-dependencies2023.0.0spring-cloud-starter-gateway4.1.0Nacosv2.3.0 二、原因分析 在 Spring Cloud Gateway 的早期版本中,Ribbon 被用作默认的负载均衡器。随着Spring Cloud的…

如何使用 Mermaid、GitHub 和 VSCode 用代码创建关系图二

Mermaid 系列 如何使用 Mermaid、GitHub 和 VSCode 用代码创建关系图一 1. 如何使用 Mermaid 生成图表 Mermaid 是一个基于 JavaScript 的工具,可将 Markdown 样式的文本转换为动态图表,让您可以毫不费力地创建和修改它们。 Mermaid 使使用简单的文…

爬虫学习笔记-scrapy安装及第一个项目创建问题及解决措施

1.安装scrapy pycharm终端运行 pip install scrapy -i https://pypi.douban.com/simple 2.终端运行scrapy startproject scrapy_baidu,创建项目 问题1:lxml版本低导致无法找到 解决措施:更新或者重新安装lxml 3.项目创建成功 4.终端cd到项目的spiders文件夹下,cd scra…

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

本节最终效果演示 文章目录 本节最终效果演示系列目录前言修改鼠标光标和中心提示图鼠标光标素材修改默认鼠标光标修改中心提示图 拾取提示弹窗简单绘制UI拾取弹窗功能 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使…

关于JVM常见的十道面试题

方法区、永久代和元空间有什么区别? 方法区、永久区和元空间是Java虚拟机用于存储类信息的区域,它们在不同的Java虚拟机版本有所不同: 方法区:方法去是一块用于存储类的结构信息、常量、静态变量、即时编译器编译后的代码等数据…

R语言基础学习-02 (此语言用途小众 用于数学 生物领域 基因分析)

变量 R 语言的有效的变量名称由字母,数字以及点号 . 或下划线 _ 组成。 变量名称以字母或点开头。 变量名是否正确原因var_name2.正确字符开头,并由字母、数字、下划线和点号组成var_name%错误% 是非法字符2var_name错误不能数字开头 .var_name, var.…

【Linux C | 网络编程】详细介绍 “三次握手(建立连接)、四次挥手(终止连接)、TCP状态”

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

稀疏场景高性能训练方案演变|京东广告算法架构体系最佳实践

近年来,推荐场域为提升模型的表达能力和计算能力,模型规模和计算复杂度大幅增加,同时,高规格硬件资源为模型迭代、算法优化带来了更大的机遇和挑战。为了应对模型规模和算力升级带来的存储、IO和计算挑战,京东零售广告…

Redis核心技术与实战【学习笔记】 - 9.如何避免单线程模型的阻塞

概述 Redis 被广泛应用的原因是因为它支持高性能访问。所以,我们要重视所有可能影响 Redis 性能的因素(如命令操作、系统配置、关键机制、硬件配置等)。 影响 Redis 性能的 5 大方面的潜在因素分别是: Redis 内部的阻塞式操作C…

leetcode209长度最小的子数组|滑动窗口算法详细讲解学习

滑动窗口是一种基于双指针的一种思想,两个指针指向的元素之间形成一个窗口。 分类:窗口有两类,一种是固定大小类的窗口,一类是大小动态变化的窗口。 简而言之,滑动窗口算法在一个特定大小的字符串或数组上进行操作&…

git clone常见问题一览及解决方法

在使用Ubuntu下,终端运行git clone命令时会遇见许多问题,本文主要针对一些常见的问题进行整理。关于换源问题,推荐使用小鱼的一键换源。 1.git clone 速度过慢 1.1 魔法 这个方法不做过多赘述,ubuntu下个人使用发现体验良好&am…

Websocket基本用法

1.Websocket介绍 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 应用场景: 视频弹幕网页聊天体育实况更新股票基金…