在 markdown 中使用中文符号
本文最后更新于:2024年2月16日 上午
问题
最近再次碰到 markdown 对中文的支持问题,由于这个问题已经长期存在,所以想谈一下现状和解决方法。当同时使用中文符号和粗体/斜体时,就会出现问题。
例如
**真没想到我这么快就要死了。**她有些自暴自弃地想着。
会被渲染为
**真没想到我这么快就要死了。**她有些自暴自弃地想着。
实际上,这种情况还有很多,几乎所有中文符号都无法被正常渲染。
示例 | 渲染 |
---|---|
**真,**她 |
**真,**她 |
**真。**她 |
**真。**她 |
**真、**她 |
**真、**她 |
**真;**她 |
**真;**她 |
**真:**她 |
**真:**她 |
**真?**她 |
**真?**她 |
**真!**她 |
**真!**她 |
**真“**她 |
**真“**她 |
**真”**她 |
**真”**她 |
**真‘**她 |
**真‘**她 |
**真’**她 |
**真’**她 |
**真(**她 |
**真(**她 |
**真)**她 |
**真)**她 |
**真【**她 |
**真【**她 |
**真】**她 |
**真】**她 |
**真《**她 |
**真《**她 |
**真》**她 |
**真》**她 |
**真—**她 |
**真—**她 |
**真~**她 |
**真~**她 |
**真…**她 |
**真…**她 |
**真·**她 |
**真·**她 |
**真〃**她 |
**真〃**她 |
**真-**她 |
**真-**她 |
**真々**她 |
真々她 |
这种情况有多常见呢?
根据吾辈之前维护同人小说的经验,在一本 80w 字的小说中出现了 2700 次以上,可以在《魔法少女小圆 飞向星空》的项目中搜索 /\*\*.*?[,。、;:?!“”‘’()【】《》—~…·〃-々]\*\* /
找到真实的用例。
解决方法
那么,如何解决呢?现在可以通过加空格、零宽度字符或者将符号移动到粗体外面。
示例 | 渲染 |
---|---|
**真,** 她 |
真, 她 |
**真,**​她 |
真,她 |
**真**,她 |
真,她 |
第一种方法会呈现出非预期的渲染,第二种方法输入很困难,最后一种方法则是必须改变输入,和第一种有类似的问题。
例如 docusaurus 就推荐了第一种方法,并结合 markdown 解析插件来自动清理粗体后面的多余空格。原本 **真,** 她
会渲染为 <p><strong>真,</strong> 她</p>
,但通过插件处理后会变成 <p><strong>真,</strong>她</p>
。
吾辈也为 mdast(remark 底层库) 实现过一个类似的插件,参考
1 |
|
使用
1 |
|
吾辈也为 markdown-it 实现了这个插件,参考:https://github.com/mark-magic/mark-magic/blob/77f9b1571a7d96847fc39e0aa8504ed994a64b71/packages/plugin-docs/src/assets/config.ts#L13-L42
进展
尽管上面的解决方法还算不错,但对于使用 markdown 编写大量内容的人而言,它仍然不够直观。尤其是不检查渲染结果就不可能知道是否忘记添加了额外的空格,这在上面提到的小说中非常明显,当内容增加到一定程度时,这种检查就变得非常烦人。尤其是从外部来源(转换)得到一个 markdown 时,这可能会非常常见。
commonmark 官方目前又开始在推进这个问题了,距离问题最初提出已经过去了 4 年,想要关注进展可以关注 issue commonmark/commonmark-spec#650。
尽管官方规范如果定义,那么问题将会极大的解决。但考虑到规范的定义和实现是漫长的,所以目前吾辈也在尝试编写 mdast 插件自行处理解析部分,以处理上面提到的那个中文符号示例列表。相关代码参考: https://github.com/rxliuli/liuli-tools/blob/82d81eeb0d661ad1338d04d1a75f173764dea9bc/packages/markdown-util/src/cjk.ts#L46-L77
总结
尽管 markdown 对 cjk 的支持有诸多不顺,但 markdown 作为一种开放的文本格式仍然很棒,所有文本数据采用 markdown 并根据需要分发为不同的格式似乎是最好的。