教程 · PDF → Markdown

PDF 转 Markdown,为什么结构是猜的

这儿别的转换器读的都是文件里真有的结构。这一个读不到,因为 PDF 里没有结构。

PDF 存的是带字号的字符和它们的坐标。「这是个标题」这句话不在文件里。所以结构是推断出来的 —— 知道它是怎么推的,就知道它什么时候会推错。

去转换器

PDF 里没有结构

PDF 是个打印格式。它的活儿是把对的字形放到纸上对的位置,办法是存一段段带位置和字体的文字。文件里没有任何一处说哪一段是标题、哪儿是段落结尾、这六行是个项目符号列表。

所以 Word 文档是「转换」,PDF 是「重建」。下面写的每一条都是启发式规则,每条规则都有它判错的情况。这就是为什么无论看起来正不正常,每次转 PDF 都会在输出上方给出一条提示。

手上有原始的 .docx 就用它。那个能正经转,因为结构真在里面。

标题是怎么找出来的

先算正文字号:把每行的字号按它含多少字符加权统计一遍,最常见的那个胜出。按字符数而不是按行数加权是有讲究的 —— 一行长正文对「正文字号是多少」的说服力,比一行短标题大得多。

然后:明显比正文大、而且短的行算标题。字号比例定级别:1.6 倍以上是 #,1.35 倍是 ##,1.15 倍是 ###。原来的标题层级已经没了,所以留下来的只是相对关系 —— 这几个标题彼此是同一级。

长度上限是 120 个字符,它挡的是一种具体的判错:一份文档开头那段正文用大字排,那不是标题,而单看字号分不出来。长度能分出来。

这条也是最常猜漏的一条。用字重而不是字号做标题的文档 —— 加粗但和正文同样大 —— 完全没有字号信号,那些标题出来就是段落。

页眉页脚、分段和列表

页眉页脚在两个条件同时成立时被丢掉:比正文小,而且落在离上下边缘 9% 页高以内。用比例而不是固定值,所以 A4 和 Letter 表现一致。不然一个页码或者一个「机密」水印会在正文里打断你四十次。

分段看的是行间垂直空隙有没有超过这行自己字号的 1.8 倍。PDF 就是这么表达一次分段的,因为里面没有段落标记可读。

列表看行首字符:一个项目符号字形(•、·、▪、◦、‣、∙),或者最多三位数字后面跟一个点或者右括号。用别的方式画出来的列表,在转换器眼里不是列表。

被行尾断开的词

PDF 会在行尾用连字符断词,直接拼起来你会拿到「re- port」。规则是:一行以连字符结尾、下一行以小写字母开头,就把这两行拼回一个词 —— 这个组合几乎每次都是断行连字符。

下一行是大写字母的时候连字符留着。「state-of-the-art」在「state-」后面断开,连字符会保留,这是对的,因为那一个是词的一部分。

中文、日文、韩文的行之间不加空格。这些文字本来不用空格分词,每次断行插一个空格就是往句子中间塞一个缝。

PDF 里的两行
The quarterly re-
port is attached.
Markdown
The quarterly report is attached.

扫描件什么都出不来

如果一页是文字的图片 —— 扫描、拍照、传真 —— 文件里没有字符可读,只有一张位图。转换器会明说然后停下,而不是回一个空文档让你以为是 bug。

从那种页面里取文字要靠 OCR,这个工具没有这个能力。一份有些页是扫描、有些不是的 PDF,能转的页会转,出来是空的那些会列出页码,最多列六个。

两个上限:25 MB 和 500 页。都是为了不让浏览器标签页卡死 —— PDF 是在你的浏览器里渲染的,没有服务器参与。

多栏排版怎么办

双栏是最难的一种,只能尽力。文字按文件里存的顺序读,做得规矩的双栏 PDF 是一栏读完再读下一栏,做得不规矩的是两栏一行一行交替。读之前没有可靠的办法知道你手上是哪一种。

表格和公式是同一个故事:PDF 里的表格是几根线加摆在坐标上的文字,没有任何东西标明它是个表格。预期是拿到几行分开的文字,而不是一张竖线表格。

准备手工修的话把页标记打开。它会在每页前面插一个 HTML 注释,这样你能找到出问题那段来自第几页,回去对照原文。

开了页标记
…第一页结束。
Markdown
…第一页结束。

<!-- page 2 -->

## Method

把 PDF 拖进来,然后读一下输出上方的提示 —— 它会说哪些页跳过了,也会提醒你结构是推断出来的。全程在你的浏览器里读,文件不上传。

PDF → MD