

在 markdown 中使用中文符号 - rxliuli blog
source link: https://blog.rxliuli.com/p/2029b35ae4094a48a3073f998f10af9c/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在 markdown 中使用中文符号
本文最后更新于:2024年2月16日 上午
最近再次碰到 markdown 对中文的支持问题,由于这个问题已经长期存在,所以想谈一下现状和解决方法。当同时使用中文符号和粗体/斜体时,就会出现问题。
**真没想到我这么快就要死了。**她有些自暴自弃地想着。
会被渲染为
**真没想到我这么快就要死了。**她有些自暴自弃地想着。
实际上,这种情况还有很多,几乎所有中文符号都无法被正常渲染。
示例 | 渲染 |
---|---|
**真,**她 |
**真,**她 |
**真。**她 |
**真。**她 |
**真、**她 |
**真、**她 |
**真;**她 |
**真;**她 |
**真:**她 |
**真:**她 |
**真?**她 |
**真?**她 |
**真!**她 |
**真!**她 |
**真“**她 |
**真“**她 |
**真”**她 |
**真”**她 |
**真‘**她 |
**真‘**她 |
**真’**她 |
**真’**她 |
**真(**她 |
**真(**她 |
**真)**她 |
**真)**她 |
**真【**她 |
**真【**她 |
**真】**她 |
**真】**她 |
**真《**她 |
**真《**她 |
**真》**她 |
**真》**她 |
**真—**她 |
**真—**她 |
**真~**她 |
**真~**她 |
**真…**她 |
**真…**她 |
**真·**她 |
**真·**她 |
**真〃**她 |
**真〃**她 |
**真-**她 |
**真-**她 |
**真々**她 |
真々她 |
这种情况有多常见呢?
根据吾辈之前维护同人小说的经验,在一本 80w 字的小说中出现了 2700 次以上,可以在《魔法少女小圆 飞向星空》的项目中搜索 /\*\*.*?[,。、;:?!“”‘’()【】《》—~…·〃-々]\*\* /
找到真实的用例。
那么,如何解决呢?现在可以通过加空格、零宽度字符或者将符号移动到粗体外面。
示例 | 渲染 |
---|---|
**真,** 她 |
真, 她 |
**真,**​她 |
**真,**她 |
**真**,她 |
真,她 |
第一种方法会呈现出非预期的渲染,第二种方法输入很困难,最后一种方法则是必须改变输入,和第一种有类似的问题。
例如 docusaurus 就推荐了第一种方法,并结合 markdown 解析插件来自动清理粗体后面的多余空格。原本 **真,** 她
会渲染为 <p><strong>真,</strong> 她</p>
,但通过插件处理后会变成 <p><strong>真,</strong>她</p>
。
吾辈也为 mdast(remark 底层库) 实现过一个类似的插件,参考
import { Transform } from 'mdast-util-from-markdown'
export function clearStrongAfterSpace(): Transform {
return (root) => {
visit(root, (it) => {
if (it.type === 'paragraph') {
const children = (it as Paragraph).children
children.forEach((it, i) => {
if (it.type === 'strong') {
const next = children[i + 1]
const s = (it.children[0] as Text).value
if (s) {
const last = s.slice(s.length - 1)
if (
next &&
next.type === 'text' &&
',。、;:?!“”‘’()【】《》—~…·〃-々'
.split('')
.includes(last) &&
next.value.startsWith(' ')
) {
next.value = next.value.trim()
}
}
}
})
}
})
return root
}
}
import { toHast } from 'mdast-util-to-hast'
import { toHtml } from 'hast-util-to-html'
import { fromMarkdown } from 'mdast-util-from-markdown'
import { clearStrongAfterSpace } from '../cjk'
const render = (s: string) =>
toHtml(
toHast(
fromMarkdown(s, {
mdastExtensions: [
{
transforms: [clearStrongAfterSpace()],
},
],
}),
)!,
)
console.log(render('**真,** 她')) // `<p><strong>真,</strong>她</p>`
吾辈也为 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 并根据需要分发为不同的格式似乎是最好的。
</div
Recommend
-
13
首先我们要在客户端(本机)生成密钥对 这里的密钥对是 Public key,具体请参考 公开密钥加密
-
6
假若我没有看见光明,我本可以忍受黑暗。 下面是吾辈在使用 Chrome 遇到的一些不舒服的地方,以及对应的解决方法。一切皆是为了一个目标:提高浏览器的使用体验! 在之前吾辈也未曾对字体有过什么注...
-
15
Spring Mongo Data 使用 Sp_ 2020年4月18日 晚上 1.4k 字 ...
-
5
esdoc 官网, 博客地址, 示例项目 在尝试过使用
-
9
假若没有看见光明,我本可以忍受黑暗。 自上家公司从去年 5 月份开始成功推广 react 之后,很长一段时间吾辈一直在使用它,而今年,离职之后新的公司再次使用 vue3,再次见证了两个 team 踏入了同一条河流。不过 vue 作者说...
-
8
官网, GitHub Maven 已经是 Java 事实上的依赖管理标准工具了,所以学习使用 maven 有益无害。 必须已经安装了 JDK...
-
10
使用 jscodeshift 做重构 rxliuli blog
-
11
解决使用 mPDF 导出 PDF 时中文及符号乱码问题 后端开发 · 实用资源 / ...
-
9
使用 vitest 做单元测试 rxliuli blog ...
-
7
使用 vitepress 时生成 rss rxliuli blog
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK