Markdown 文件:带约定的纯文本,而且不止一种
.md 文件到底是什么、为什么没有两个渲染器对它的理解完全一致、以及标题和列表是怎么从一份根本没记录过它们的 PDF 里重建出来的。
速览
- 类型
- 文档
- 扩展名
- .md, .markdown
- MIME 类型
- text/markdown
- 别称
- MD
一个 .md 文件就是一个文本文件。没有容器,没有压缩,里面没有任何二进制内容——用记事本打开,你看到的就是它全部的内容。它的格式是约定而不是标记:行首的 # 表示标题,一个连字符表示列表项,而一个理解这套约定的渲染器会把它们变成 HTML。这就是它的全部想法,也正是它熬过了同代所有富文本编辑器的原因:文件在被渲染之前就是可读的,而且当你写它用的那个工具消失之后,它依然可读。
展开说明
麻烦在于:并不存在唯一的 Markdown。2004 年的最初实现留下了大量未定义的情形,于是每个渲染器各自给出了不同的答案;CommonMark 的存在就是为了把这些歧义钉死,而 GitHub Flavored Markdown 又在它之上加了表格、任务列表和删除线。这个局面是被正式承认的:2016 年 3 月 RFC 7763 把 text/markdown 注册为媒体类型时,注册里带了一个 variant 参数,正是因为「说一个文件是 Markdown」并没有说清它是哪一种 Markdown。本站产出的是 text/markdown 加 UTF-8,而且只用所有方言都认同的写法——井号标题、空行分段、连字符项目符号和分隔线。
把 PDF 转成 Markdown,意味着要造出 PDF 从来没有过的结构。PDF 记录的是字号而不是标题,所以页面上出现的字号会被排序,最大的六档成为六级标题;一行只要比正文大,就会成为标题,不管作者当初是不是这么想的。列表更糟:PDF 里压根没有「列表」这种构造,你看见的那个圆点实实在在就是文本里的一个字符,所以列表能保住的唯一办法,是认出那个字符并把它改写成连字符。带编号的条目不需要这种帮忙——「1. 」和「1) 」本来就是 Markdown,本来就是当列表写的。
有两个细节值得知道,因为它们会改动文字本身。以连字符结尾的行,会被当作一个被断行拆开的单词,重新接上时去掉那个连字符;而连续的中文或日文行,接起来时中间不加空格,因为这两种文字本来就不在那里放空格。页与页之间用一条分隔线隔开,所以一份十三页的文档会带着十二条分隔线到达。如果 PDF 是没有文本层的扫描件,会先由与 PDF 转 Word 相同的那个识别模型,在你自己的机器上从页面图像里把字读出来。
把其他格式转成 Markdown
Markdown常见问题
.md 文件就只是个文本文件吗?
是的。没有容器,没有压缩,没有任何二进制内容。任何文本编辑器都能打开它,而那些记号——#、-、**——都是你可以照原样读出来的普通字符。
我拿到的是哪一种 Markdown?
只有所有方言都认同的那部分:井号标题、空行分段、连字符项目符号和分隔线。这里没有任何东西依赖 GitHub 或 CommonMark 的扩展,所以你粘到哪里,渲染出来都一样。
文档里为什么有几行横杠?
那是分页。每一条都是一根分隔线,标出上一页 PDF 在哪里结束、下一页从哪里开始,所以一份十三页的文档会返回十二条。
有个标题的级别不对,为什么?
级别是按字号排出来的,因为 PDF 存的是字号而不是标题。当一份文档用字号来强调而不是表示层级时——一段引文、一行放大的首句——排序会跟着字号走,于是级别就错了。
表格能保住吗?
画了框线的表格可以——会变成 Markdown 表格,第一行作为表头。扫描页上的表格会变成普通的行,因为扫描件里没有可读的框线。如果转换就是为了表格,PDF 转 Excel 会把每张表放进可以直接处理的行和列。
扫描版 PDF 能用吗?
能。当没有文本层时,会有一个 AI 识别模型在你的浏览器里运行,从页面图像里把字读出来。此时标题按测量出的行高排序而不是按字号,全程不上传。