Markdown 里的中英文空格

Markdown 写作约 5 分钟

中文和英文字母、数字之间习惯加一个普通空格,写成「使用 Swift 开发」「第 3 章」,而不是「使用Swift开发」,这是中文文案排版里的约定,不是语法规则,Markdown 本身也不管这件事,字符原样进原样出。妙言「编辑」菜单里有两个命令会加这个空格,「排版净化」没有快捷键,还会顺带修正中文标点,⌘⇧L 对应的「文档排版」则是内置的 Prettier 格式化器顺手加上的。

为什么要加这个空格

汉字是方块字,等宽排列,拉丁字母窄而且宽度不一,两者直接挨在一起,视觉上会显得挤。传统排版的做法是在中间留一小段间距,不是一个完整的空格。W3C 的中文排版需求文档 clreq 写的是,横排时原则上汉字与西文字母、数字之间使用不多于四分之一个汉字宽的字距或空白,西文、数字出现在行首或行尾时则无须加入空白。

纯文本里没有这种「字距」,所以大家只能手动敲一个真空格。流传最广的写法是 中文文案排版指北,要求中英文之间、中文与数字之间、数字与单位之间都加空格,它自己的示例是「在 LeanCloud 上,数据存储是围绕 AVObject 进行的」,行内代码和英文单词一样处理。

这份指北是风格约定,不是国家标准,很多正式出版的中文也不这么写。对自己的笔记来说,关键是前后一致,因为「Swift开发」和「Swift 开发」在搜索和 diff 里是两个不同的字符串,一半有空格一半没有的笔记库最难维护。

常见例外

指北里有几条在日常写作中经常碰到。

  • 全角标点和其他字符之间不加空格,写「刚刚买了一部 iPhone,好开心!」,不写「iPhone ,好开心」,因为逗号、句号这类标点自带留白。
  • 度数和百分号紧跟数字,写「90°」「15%」,指北明确把「15 %」列为错误;其他单位则要加空格,比如「10 Gbps」「20 TB」。
  • 产品名按官方写法,指北的例子是「豆瓣FM」,官方就是不带空格的。

另外有两类来自 Markdown 本身。代码块和行内代码里的内容一个字符都不能动,空格在那里是数据;URL、文件路径、链接目标和双链标题里多一个空格就会让链接失效。

妙言里怎么做

妙言 4.5.0 的「编辑」菜单里有两个命令都会改间距,做的事情多少不一样。

「文档排版」(英文界面叫 Format,快捷键 ⌘⇧L)会调用内置的 Prettier Markdown 格式化器整理 Markdown 结构,比如列表标记和表格对齐。它内置的是 Prettier 2.x,这一代还会在汉字和拉丁字母、数字之间插空格,所以「使用Swift开发」在这里也会变成「使用 Swift 开发」,Prettier 3.0 之后去掉了这个行为。除此之外它不管中文,「你好,世界」里的半角逗号不会改,全角逗号前的空格不会删,行内代码两侧也不补空格。

「排版净化」(英文界面叫 Clean Typography)是专门为中文写的那个,没有快捷键,一次处理当前打开的整篇笔记,结果进入撤销栈,不满意按 ⌘Z 就能退回;没有可改的内容时会提示排版已经很干净。它和「文档排版」一样在预览模式下不能用,要先退出预览。

按源码,它做这几件事。

  • 汉字或假名与 ASCII 字母、数字相邻时补一个空格,两个方向都补,「使用Swift开发」变成「使用 Swift 开发」,「第3章共10节」变成「第 3 章共 10 节」,已经有的空格不动。
  • 汉字后面紧跟的半角 , ; : ! ? . 如果是在结束一个分句,就换成全角,「你好,世界」变成「你好,世界」,而「3.5」「10:00」这种数字里的点和冒号不会动。
  • 全角标点两侧多余的空格会被删掉。
  • 全角字母和数字改回半角,「等等...」变成「等等……」,汉字之间单独一个 em dash 会换成逗号,连续两个的正经中文破折号会保留。
  • 连续多个空行折成一个。

它不会在数字和拉丁字母单位之间补空格,所以「10Gbps」还是「10Gbps」,「90°」「15%」也不会变,因为这些符号不算字母或数字;它同样不认识「豆瓣FM」这类产品名,跑完以后要自己扫一眼。

哪些地方不会被改

清理时每一行会先拆成受保护和普通两种片段。受保护的包括围栏代码块(反引号或波浪线,引用块里的也算)、缩进代码块、行内代码、$...$ 行内公式和 $$ 块级公式、链接与图片的目标、[[双链]]、裸 http 和 https 地址、[ref]: target 与 [^1]: note 这类引用定义,还有文件开头的 front matter。行尾两个空格的硬换行也会保留。

行内代码有个小处理,里面的文字不动,但两侧会补空格,使用`git status`命令 变成 使用 `git status` 命令,和指北一致。链接文字会被处理,目标不会,「看文档3吧」变成「看文档 3吧」。

还有一个细节,「我有$100和$200的钱」里的美元金额不会被当成公式,会按普通文字补空格。

预览里还有一层

和编辑动作无关,妙言的预览页用的是基于 Heti 的排版样式表,.heti 容器设置了 text-autospace: normal。这个 CSS 属性让浏览器引擎自己在汉字和拉丁字母、数字之间补一小段间距,文件里不需要有空格。MDN 的兼容表显示 Safari 从 18.4 开始支持,所以你能不能看到取决于系统的网页引擎版本。不管怎样,它只影响预览,文件里仍然是你敲的内容。

这也是为什么一篇没加空格的笔记在妙言预览里看着正常,贴到 GitHub、聊天窗口或别的编辑器里就显得挤。把真空格写进文件是最不依赖渲染器的办法。

一批笔记怎么处理

4.5.0 的这两个命令都只处理当前打开的这篇,菜单里没有批量命令。已有一整个文件夹的话,可以一篇篇点,或者在应用外用脚本处理。指北里链接的 pangu.js 就是这个思路的代表,具体用哪个工具都先在文件夹副本上试,并检查它怎么处理代码块。笔记本来就是普通 .md 文件,复制整个文件夹就是最简单的备份。

批量处理以后用 diff 看一遍结果,重点看代码块、URL 和产品名。

怎么检查结果

  • 在支持正则搜索的编辑器里用 [一-鿿][A-Za-z0-9]|[A-Za-z0-9][一-鿿] 搜汉字直接挨着字母或数字的位置,搜不到说明间距一致。
  • 再跑一次「排版净化」,提示「排版已经很干净了」说明已经稳定。
  • 随手看一个代码块和一个带中文的链接有没有被误改。

其他语法和妙言实际能渲染什么,看 Markdown 语法速查与 GFM 差异,笔记保持成普通文件也让批量处理更安全,见 本地优先的 Markdown 笔记怎么管。

常见问题

标题和文件名也要加空格吗?

标题和正文一样处理。文件名和双链标题看你自己,但要统一,因为双链要和笔记标题对得上,空格也算在内。

全角逗号前面加空格对吗?

不对,指北把它列为错误,「排版净化」会把它删掉,「文档排版」不会。

这个空格算 Markdown 语法吗?

不算。Markdown 解析器会保留你敲的字符,所以间距要么写在文件里,要么靠渲染器的排版样式,比如上面说的预览。