为什么某些Unicode字符会错位?东亚宽度问题与mermaid-ascii的解法
【免费下载链接】mermaid-asciiRender Mermaid graphs inside your terminal项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-ascii
用 mermaid-ascii 在终端里渲染流程图、时序图时,很多新手都会遇到同一个"灵异"现象:只要参与者名称里出现中文或日文,右边的竖线就集体向右"漂移",箭头对不齐边框。这不是 bug,而是**东亚宽度(East Asian Width)**问题。
什么是"东亚宽度"错位?
终端本质是一张等宽网格:每个字符占一个固定列宽的格子。英文字母、数字占 1 格,而中日韩全角字符(如"中"、"客")占2 格,组合附加符号占0 格。
如果程序天真地按"字符个数"计算宽度,就会出错:
"客户"= 2 个字符,但实际显示宽度 =4 列
│ 客户 │ ← 按字符数算宽:右边框少了2列,边框断裂 │ 客户 │ ← 按显示宽度算宽:完美对齐📐 这就是为什么同样一段 ASCII 图,纯英文标签整齐,一混入 CJK 就"错位"。
问题根源:Unicode 宽度并不唯一
Unicode 规范把字符的显示宽度分为几类,终端渲染时各取所"宽":
| 类别 | 宽度 | 典型例子 |
|---|---|---|
| Wide(W) | 2 列 | 汉字、假名、全角标点 |
| Ambiguous(F) | 1 或 2 列 | ○、①、制表符类符号 |
| Neutral(N) | 1 列 | 字母、数字、┌─┐等绘图字符 |
| Zero-Width(ZW) | 0 列 | 组合变音符、零宽空格 |
其中最阴险的是Ambiguous 类:同一个字符在英文终端占 1 列、在 CJK 终端占 2 列,行为随环境而变。
mermaid-ascii 的解法:量"宽度"而不是数"字符"
mermaid-ascii 的核心思路很简单——所有布局计算都基于显示宽度,而非 rune 个数:
- 时序图渲染器在 pkg/sequence/renderer.go 中实现了
displayWidth():逐字符测量宽度后累加,全角记 2、零宽记 0,再据此决定边框、箭头和生命线的落点。 - 流程图标签在 pkg/graph/label.go 中用
runewidth.StringWidth()计算每行真实宽度,保证盒子高度和边距一致。 - 宽度测量依赖成熟的
go-runewidth库,天然覆盖 Wide / Ambiguous / Zero-Width 三大类字符。
针对 Ambiguous 字符,项目还做了保守选型:在 pkg/sequence/charset.go 中,中心连接标记刻意选用o而不是○,源码注释写得很直白——○是 East-Asian-ambiguous 宽度,会在 CJK 终端里破坏列对齐。
验证:CJK 字符矩阵测试
项目内置了一整套 CJK 回归测试数据,覆盖日文、中文混排、组合变音符和零宽字符等边界场景:
- cmd/testdata/sequence/cjk_feature_matrix.txt:日文参与者 + 中文消息 + 框/框选/循环/备注的完整功能矩阵
- cmd/testdata/sequence/east_asian_participants.txt:东亚参与者对齐测试
- cmd/testdata/sequence/combining_marks_mixed_width.txt:组合附加符号与混合宽度
其中 CJK 功能矩阵的渲染结果节选(参与者"顧客 / 服务 / 監査 / 数据库"全部对齐):
│ ┌──────┐ ┌──────┐ │ ┌──────┐ ┌────────┐ │ │ 顧客 │ │ 服务 │ │ │ 監査 │ │ 数据库 │ │ └───┬──┘ └───┬──┘ │ └───┬──┘ └────┬───┘给新手的 3 个实用建议
- 终端字体:确保终端使用支持 CJK 的等宽字体(如 Sarasa / 更纱黑体),否则即使程序算对了宽度,字体本身也会把全角撑成 2.x 倍宽。
- 避免 Ambiguous 符号:在节点/参与者命名中少用
○、①这类宽度不确定的字符,换用明确的 ASCII 替代。 - 终极保险:如果运行在 CJK 终端上仍出现偏差,可加
--ascii参数切换纯 ASCII 渲染模式(见 README.md 中 "Only ASCII" 一节),纯 ASCII 在任何终端都不会错位。
理解"显示宽度 ≠ 字符数"这一个概念,你就能看懂终端 ASCII 图排版背后的所有玄机——而 mermaid-ascii 正是把这个概念贯彻到每一根边框线上的。
【免费下载链接】mermaid-asciiRender Mermaid graphs inside your terminal项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-ascii
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考