PDF 转换为什么会丢失结构,以及该怎么办
最后核对
所有 PDF 转 Markdown 的工具,包括本工具,都会时不时产出看起来很粗糙的结果:标题被降级成段落,表格被压扁成一堵文字墙,双栏页面被横着读完,句子彼此交错。
这些都不是粗心。它们直接源于 PDF 文件里究竟装了什么。一旦你知道了这一点,错误就变得可以预测——也就是说,你能提前判断自己手里哪些文档能干净转换,哪些不能。
阅读约 6 分钟
PDF 里到底有什么
文字处理软件的文档是一棵树。它记录着这段文字是二级标题、这几段属于那一节、这些单元格构成一张三列的表。外观是在显示时从这套结构推导出来的。
PDF 恰恰相反。它是一组绘制指令:把这个字形,用这个字体,以这个字号,画在这一页的这个坐标上。产生该版面的结构不会被保存——它用来算出坐标,然后就被丢弃了。
这不是格式的疏忽。PDF 在 1993 年被设计出来,就是为了保证一份文档在任何设备、任何打印机上看起来完全一致,而保证的办法就是把外观精确写死,不给重新推算留任何余地。它彻底做到了。代价是,PDF 知道每个字符在哪里,却完全不知道它们是什么意思。
所以把 PDF 转成 Markdown 不是提取,而是推断:把几何信息反过来读,猜出什么样的结构会产生这样的排布。好的转换器猜得准。但没有任何转换器能做得比猜更好,因为答案确实不在文件里。
唯一的例外:带标签的 PDF
带标签的 PDF 额外携带一棵结构树,是为无障碍访问添加的,好让屏幕阅读器能报出标题、按顺序读出表格单元格。当它存在且正确时,大部分猜测就不必要了。
但实际上二者很少同时成立。打标签是可选的,多数 PDF 生成程序不加;而在加了的那些里,又有大量产出与可见版面相互矛盾的标签——每个段落都被标成标题,或者一张表被标成一串段落。一个信任错误标签的转换器,结果会比直接忽略标签的更差。
如果 PDF 的生成过程由你掌控,而你在意转换质量,那么从 Word 或 LibreOffice 导出一份正确打了标签的 PDF,是你能做的最有用的一件事。如果你转换的是别处送来的文档,就当它们没有标签。
结构是如何从几何信息推断出来的
任何按空间关系工作的转换器,规则大体相同,值得了解——因为每一条规则都对应一种失败方式。
首先要定一个单位。正文字高——文档中出现频率最高的字号,按该字号下的字符数量加权——成为标尺,于是无论文档用 9pt 还是 14pt 排版,规则都同样适用。
然后用它去衡量其余一切。共享基线的文本片段属于同一行。被较小纵向间隔隔开的行属于同一段落,间隔更大则开启新段。明显大于正文的文本是标题,大多少决定级别。片段在共同水平位置上对齐的若干行构成表格。页面中部一条高而空的纵向带意味着分栏,因此阅读顺序应当先走完一栏再走另一栏。
本转换器大致采用以下阈值,单位是正文字高的倍数:
| H1 | 超过正文字高的 1.8 倍 |
|---|---|
| H2 | 超过正文字高的 1.4 倍 |
| H3 | 超过正文字高的 1.2 倍 |
| 同一行 | 基线相差在 ±0.35 倍正文字高以内 |
| 同一段落 | 纵向间隔不超过 1.5 倍正文字高 |
| 表格 | 2 行以上连续、在 2 个以上共同 x 坐标对齐 |
每一次失败都源自某条规则
把上面那张表当作假设清单再读一遍,错误就不再神秘了。
- 只靠字重或颜色而不改变字号来区分的标题,对基于字号的阈值来说是隐形的。一份用 11pt 加粗标题配 11pt 正文的文档,从几何上说根本没有标题。
- 含合并单元格的表格会破坏共同位置的判定,因为合并单元格占据的位置没有任何其他行使用。行不再对齐,这一块也就不再被识别为表格。
- 内容折到第二行的单元格,看起来像两行,其中一行还缺了一块。
- 过于宽松的行距会把同一段落的行推过段落分隔阈值,把它拆开;段落之间过于紧凑的间距则会把它们并成一段。
- 三栏版面、宽度不等的双栏、被通栏插图打断的栏——都会让页面中缝的判定失效。
- 以图片形式排出的文字——含文字的标志、带标签的图表、扫描页面——根本没有字形,因此既无可定位之物,也无可读之物。
哪些文档能干净转换
规律始终一致:由文字处理软件产出的单栏文档,标题明显大于正文,表格是简单的矩形,而且里面是真正的文字而非文字的图片。
这描述了大多数报告、论文、手册、学位论文、合同、会议纪要和内部文档——也就是人们要转换的绝大部分内容。它不描述杂志、宣传册、带设计信息图的年报、表单、含复杂表格的发票,以及任何扫描件。
| 转换良好 | 文字处理软件产出的报告、论文、手册、合同、纪要 |
|---|---|
| 部分可转换 | 含双栏、脚注和插图的学术 PDF |
| 转换很差 | 杂志、宣传册、表单、发票、精心设计的版面 |
| 无法转换 | 扫描件与照片,除非先做文字识别 |
从难处理的文档里拿到更好的结果
有几件事确实管用,大致按效果从大到小排列。
- 如果你能重新生成 PDF,就导出带标签的版本——更好的做法是跳过 PDF,直接转换原始文档。转换由 Word 文件生成的 PDF,永远不如转换那份 Word 文件。
- 拆分混合版面的文档。把十页正文和四页表格分开转换,好过跟一次必须同时应付两者的转换较劲。
- 把顽固的表格单独抽出来。在 60 页文档里失败的表格,当它是页面上唯一内容时往往能正确转换。
- 对于用字重表示标题的文档,做好手工修标题的准备。那是一轮查找替换,不是重新录入的活。
- 对扫描件,先跑文字识别。没有捷径:任何解析器都找不到从未以文字形式编码的文字。
永远读一遍结果
真正耗费时间的失败,不是那种明显崩掉的转换,而是悄悄丢东西的那种——一个脚注、表格的最后一行、落在检测到的栏外的一行——然后交给你一份干净、可信、内部却有个洞的 Markdown。
在依赖它之前,把转换后的 Markdown 与原文对照着通读一遍,尤其留意表格、所有数字,以及每页最后几行。悄无声息的丢失就集中在那里。