ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Prettier 韩文(Hangul)Markdown 格式化解析:`splitCjkText/korean.md` 测试用例深度解读

2026/9/19 22:46:09 拓冰建站 浏览量
Prettier 韩文(Hangul)Markdown 格式化解析:`splitCjkText/korean.md` 测试用例深度解读 Prettier 韩文HangulMarkdown 格式化解析splitCjkText/korean.md测试用例深度解读【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier本文聚焦 Prettier 的 Markdown 排版引擎对韩文Hangul文本的换行与空格处理规则。围绕 korean.md 这一官方测试用例结合 whitespace.js 与 utilities.js 源码你将从“韩文为何被当作类拉丁词处理”“韩文与中英文混排的换行规则”“快照测试如何锁定行为”三个层面掌握 Prettier 处理多语言 Markdown 段落的内在机制与实战验证方法。一、为什么专门为韩文准备一个测试文件Prettier 对 Markdown 段落的处理并不是简单地“按空格折行”。对于东亚文字不同语言的书写习惯差异巨大中文、日文不使用空格分词字符与字符之间没有显式词边界韩文Hangul虽然使用表音文字但用空格分隔单词书写习惯更接近拉丁文英文等拉丁文字完全依赖空格分词。Prettier 在 utilities.js 的注释中明确写道Korean uses space to divide words, but Chinese Japanese do not. This is why Korean should be treated like non-CJK.这段注释直接定义了韩文在 Prettier Markdown 排版中的“身份”韩文被归类为KIND_K_LETTERk-letter与KIND_NON_CJKnon-cjk享有近乎相同的换行语义而不是像汉字、假名那样被当作KIND_CJ_LETTERcj-letter处理。tests/format/markdown/splitCjkText/korean.md正是为验证这一设计而准备的专项测试输入文件。它由 5 组韩文段落构成覆盖了韩文与英文混排、韩文与汉文Han混排、韩文长句折叠、韩文单字符逐行书写等典型场景。同目录下的 chinese-japanese.md、mixed.md、han-kana-alnum.md 等文件则分别覆盖中日文、中日英混排等对照组共同构成 CJK 文本分割测试矩阵。二、测试用例文件结构与运行方式2.1 文件路径与配套资源文件作用korean.md韩文格式化测试的原始输入snapshots/format.test.js.snapJest 快照记录输入与预期输出含korean.md用例format.test.js测试驱动脚本还额外注入两个动态代码片段目录下其余文件chinese-japanese.md、mixed.md、space.md、link.md、han-kana-alnum.md、symbolSpaceNewLine.md以及non-bmp/子目录与korean.md共用同一测试入口format.test.js通过runFormatTest以[markdown]解析器、{ proseWrap: always }选项批量运行。2.2 如何复现该测试在仓库根目录执行# 仅运行韩文 Markdown 用例 yarn jest tests/format/markdown/splitCjkText --runTestsByPath tests/format/markdown/splitCjkText/format.test.js # 更新快照当格式化行为有意变更时 yarn jest tests/format/markdown/splitCjkText --updateSnapshot快照头部会打印本次运行的选项parsers: [markdown] proseWrap: always printWidth: 80 (default)这说明韩文用例是在proseWrap: always强制折行与默认printWidth: 80下验证的——只有在该模式下换行逻辑才会被充分触发。三、korean.md 五组用例的预期行为全解读以下每组用例均对照快照 format.test.js.snap 中的 input/output 逐段分析。3.1 韩文 英文混排无空格粘连输入首行예문Latin예문Latin 예문Latin예문 Latin예문Latin 예문 Latin 예문输出保持不变예문Latin예문Latin 예문Latin예문 Latin예문Latin 예문 Latin 예문这是韩文与英文无空格粘连예문Latin与有空格混排的基准行。行为要点韩文예문与英文Latin之间本来没有空格格式化后不会强行插入空格——Prettier 不负责“加空格”只负责决定“已有空格/换行如何处理”已有空格被保留并作为折行点候选由于该行在 80 列以内不触发折行。3.2 韩英混排段落的折叠与重新折行输入是同一句韩英混排句子以 3 种不同书写方式重复 5 遍单行连续书写 2 遍、按词逐行书写 2 遍、又单行书写 1 遍。输出将全部统一为按 80 列重新折行的连续段落한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다. 한국어와 English를 섞어 보았습니다.关键结论“按词逐行书写”的人工换行被折叠回段落韩文与英文之间的\n均被转换为空格。这正对应 whitespace.js 中的规则// \n between non-CJK or Korean characters always can be converted to a space. // Korean Hangul simulates Latin words. See issue #6516 (isNonCJKOrKoreanLetter(previousKind) isNonCJKOrKoreanLetter(nextKind)) || // Han Hangul: same way preferred (previousKind KIND_K_LETTER nextKind KIND_CJ_LETTER) || (nextKind KIND_K_LETTER previousKind KIND_CJ_LETTER)isNonCJKOrKoreanLetter的实现whitespace.js把KIND_NON_CJK与KIND_K_LETTER归为一类所以“韩文↔英文”“韩文↔韩文”之间的换行一律允许转空格。3.3 韩文 汉文Han混排折行避开汉文输入역대 대통령은 李承晩 과 許政 과 尹潽善 과 朴正熙 과 崔圭夏 과 朴忠勳 과 全斗煥 과 盧泰愚 과 金泳三 과 金大中 과 盧武鉉 과 李明博 과 朴槿惠 과 文在寅 과 尹錫悅 과 음...输出注意折行位置역대 대통령은 李承晩 과 許政 과 尹潽善 과 朴正熙 과 崔圭夏 과 朴忠勳 과 全斗煥 과 盧泰愚 과 金泳三 과 金大中 과 盧武鉉 과 李明博 과 朴槿惠 과 文在寅 과 尹錫悅 과 음... 역대 대통령은 ...这是最能体现“韩文被当作拉丁词”的用例。第一行折行发生在全斗煥与과之间——即韩文과与韩文과之间而夹在中间的汉文李承晩、許政等未被拆分整组汉文与两侧韩文一起作为完整词处理。快照还展示了两种不同的书写风格输入第 40 行“李承晩 과 許政 과 …”汉文与韩文之间有空格→ 输出保留空格折行输入第 62 行“李承晩과 許政과 …”汉文与韩文之间无空格→ 输出保持无空格、仅在韩文词边界折行。两种风格互不干扰、各自保持一致验证了“不强行插入/删除 CJK 与韩文之间的空格”这一边界。3.4 韩文长句自动折行输入两段超长韩文句子含NVIDIA、RTX3000、삼성전자、TSMC等专有名词以及대한민국(듣기 (도움말·정보), 大韓民國, 영어: Republic of Korea; ROK[3])은 …这类多语言混合长句输出按 80 列在韩文词边界折行NVIDIA의 RTX3000 시리즈는 삼성전자와 TSMC에 의해 제조된다. NVIDIA의 RTX3000 시리즈는 삼성전자와 TSMC에 의해 제조된다. ... 대한민국(듣기 (도움말·정보), 大韓民國, 영어: Republic of Korea; ROK[3])은 동아시아의 한반도 중남부에 있는 공화국이다.值得注意的细节대한민국(듣기中的(与대한민국之间没有空格折行点被安排在其后ROK[3])은中的[3])与韩文은之间同样无空格且整体保留。这是因为(、[、)、]属于 ASCII 标点whitespace.js 中lineBreakBetweenTheseAndCJConvertsToSpace集合允许 CJK/韩文与这类标点之间的换行转空格但 Prettier 不会在这些位置主动制造折行。3.5 逐字符书写的韩文被重组输入中有一段把每个字符单独成行的韩文한국어와/English를/섞어/보았습니다.逐行书写输出时被重新组合为正常段落。这与 3.2 是同一规则在不同输入形态下的表现韩文词之间的换行可无损转换为空格因此即使作者以“每词一行”的极端方式书写Prettier 也能将其规整为可读的连续文本。四、源码级原理从 splitText 到 printWhitespace 的完整链路4.1 词法切分韩文被标记为 k-letterMarkdown 段落文本首先在 utilities.js 的splitText中被切分为word与whitespace两类节点。切分分两层按空白切分text.split(/([\t\n ])/)分出非空词块与空白块按 CJK 字符切分用 constants.evaluate.js 导出的CJK_REGEXP将每个词块再切为“非 CJK 词 单个 CJK 字符”。每个word节点会被赋予四种kind之一utilities.jskind含义isCJnon-cjk拉丁词、数字等falsek-letter韩文Hangul\p{Script_ExtensionsHangul}见 utilities.jsfalsecj-letter汉字、假名等单个 CJK 字符truecjk-punctuationCJK 标点含\u3000全角空格、\uFF5E等见 constants.evaluate.jstrue关键赋值逻辑utilities.js// Korean uses space to divide words, but Chinese Japanese do not // This is why Korean should be treated like non-CJK if (K_REGEXP.test(innerToken)) { appendNode({ type: word, value: innerToken, kind: KIND_K_LETTER, isCJ: false, ... }); continue; } appendNode({ type: word, value: innerToken, kind: KIND_CJ_LETTER, isCJ: true, ... });可以看到韩文 token 的isCJ被显式置为false这是后续所有换行决策的分水岭。4.2 换行决策三个核心函数切分完成后空白节点值为 、\n或在打印阶段由 whitespace.js 的printWhitespace处理其决策分两步第一步\n能否转为空格——lineBreakCanBeConvertedToSpacewhitespace.js韩文与非 CJK、韩文与韩文之间总是可以转空格韩文与汉字/假名Han 与 Hangul之间同样允许与浏览器行为保持一致涉及 CJK 标点、或汉字/假名与汉字/假名之间不转换介于 CJK 与 ASCII 标点之间允许转换。第二步这个空白能否作为折行点——isBreakablewhitespace.js仅当proseWrap always且不在链接、表格单元格、标题等单行节点内时才可折行韩文与汉字/假名之间允许折行只要前/后任一是 CJK 字符previous.isCJ || next.isCJ不折行——由于韩文isCJ false韩文词边界天然获得折行资格这正是 korean.md 中折行点几乎都落在韩文词边界的原因两个汉字/假名之间不折行对应[2]注释中 Chrome/Safari 对 CJK 间换行的新行为。第三步输出空白形态——printWhitespacewhitespace.js可转空格且可折行 → 输出line可折行的空格可转空格但不可折行 → 输出 不可转空格 → 输出。4.3 一个关键特例全角空格与韩文appendNode中有一条保护规则utilities.js当相邻 word 的边界含\u3000全角空格时不插入值为的“假空白”节点避免在标点或全角空格两侧产生意外的拼接。\u3000与\uFF5E被同时归入PUNCTUATION_REGEXPconstants.evaluate.js即“按标点对待”。这解释了 korean.md 之外、chinese-japanese.md 中“全 形 空白”这类全角空格文本保持原样的原因。五、运行与验证如何亲手复现韩文格式化5.1 使用 CLI 直接格式化在仓库根目录或已安装 Prettier 的环境中执行# 用默认 printWidth 80 与 proseWrap: always 格式化韩文文件 yarn prettier --parser markdown --prose-wrap always tests/format/markdown/splitCjkText/korean.md # 显式指定 printWidth yarn prettier --parser markdown --prose-wrap always --print-width 80 tests/format/markdown/splitCjkText/korean.md输出应与快照中的 output 段一致。若改用--prose-wrap preserve则输入中的手动换行会被原样保留不再折叠——这也是 whitespace.js 中proseWrap preserve value \n直接返回hardline的行为。5.2 快照驱动的回归保障korean.md的行为被固化在 format.test.js.snap 中。任何对splitText、lineBreakCanBeConvertedToSpace、isBreakable或printWhitespace的改动只要改变了韩文段落的折行/空格行为CI 中的快照测试就会立即失败从而强制开发者审视对韩文排版语义的破坏。此外format.test.js 还注入了两个纯代码构造的动态用例“Han 后、换行前、Han 前”的单个尾随空格构造 6 行长度递增的汉字串行宽恰为 80 的整数倍断言格式化结果为文.repeat(40 * 6)的连续文本——即 Han 字符间的单个尾随空格应被忽略CJK 标点含\u3000、\u301C、\uFF5E、\u{1F221}附近的换行移除断言标点两侧的换行被直接移除code.replace(/\n/g, )验证标点周边不产生折行。这两个用例与korean.md互补共同覆盖“字符分类 → 空白形态 → 折行资格”的完整判定面。六、边界情况与已知限制从源码注释可以明确以下边界均来自 whitespace.js 与 utilities.js 的注释与逻辑韩文与汉字/假名之间的换行行为目前[CJK punctuation][\n][Hangul]被处理为等价于[CJK punctuation][][Hangul]无空格源码注释明确指出这与 Firefox 的行为并不完全一致未来计划改为等价于[ ]有空格whitespace.js韩文与英文之间的空格插入策略源码注释whitespace.js说明“句子若整体采用 CJK 与 non-CJK 加空格风格则\n可转空格”——该判定基于isInSentenceWithCJSpaces对整句的统计whitespace.js即风格由句子内多数派决定非 ASCII 标点如〜U301C、…U2026位于词首/词尾时其邻接换行不转为空格whitespace.js源码邀请社区 PR 细化此规则proseWrap: preserve保留所有手动换行韩文词边界也不会被重新折行标题、链接、表格单元格属于单行节点SINGLE_LINE_NODE_TYPESwhitespace.js内部不做折行但链接文本isLink例外地允许\n转空格以维持链接标签的归一化形式。七、总结korean.md看似只是一份韩文测试文本实则是 Prettier 多语言排版哲学的一个浓缩标本“韩文用空格分词因此按拉丁词处理”。围绕这一原则splitText将韩文标记为k-letter且isCJ: falselineBreakCanBeConvertedToSpace允许韩文邻接换行转空格isBreakable将折行资格限定在韩文词边界最终通过proseWrap: always下的快照测试把整套行为固化为可回归验证的契约。如果你正在为中文、日文、韩文混合的 Markdown 项目配置 Prettier可以直接把 korean.md 及其快照当作行为参考若要深入了解折行决策的每一步whitespace.js 与 utilities.js 是首选的阅读入口。【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考