Han 统一:同一码点的中日韩字形
归一化 处理的是「不同码点写出同一个字」。本页正相反:U+5203(刃)只有一个码点,却在中文、日文、韩文字体里画成不同字形。这就是 Han 统一——Unicode 把中日韩历史同源的表意文字合并到同一批码点,字形差异交给字体与
lang 处理。===、正则与索引都只认码点,看不见字形;不给文本标对 lang,就会拿中文字形显示日文,码点没错而字「写错了」。
1 · 合并的边界
中日韩与越南喃字共用大量同源汉字。若按语言各编一套,汉字总量要翻几倍,码空间会爆炸且互不兼容。Unicode 的选择是合并,把同一个抽象字在各地的写法收进同一个码点,这批字即 CJK Unified Ideographs(U+4E00 起)。
合并到哪为止,由 Source Separation Rule 划定:某字若在任一来源标准(中国 GB、台湾 CNS、日本 JIS、韩国 KS)里本就分成两个字编码,Unicode 也保持分开,所以「戶 / 戸」「樣 / 様」「黑 / 黒」是不同码点,不在本页讨论之列;否则视为同一个抽象字合成一个码点,地区书写习惯造成的差异——点的位置、部件朝向、笔画连断——不体现在码点上,交给字体去画。
2 · 四语并排
同一个码点配上不同的 lang 与地区字体,屏幕上可能是四个样子。字节完全相同,差别纯粹来自字体。
注 · 看不出差别时,问题多半在字体:浏览器要先有对应地区的 CJK 字体,才能按 lang 选出不同字形。macOS 自带 PingFang SC 与 TC、Hiragino Sans、Apple SD Gothic Neo,差异通常一眼可见;某语言字体缺失时,该面板会回退成已有字体,看起来与邻格一样。
3 · 分歧字画廊
这不是个别字的特例。把常被引用的一批字横排展开,同一个码点在四种 lang 下的字形差异是系统性的:骨 上半方框的朝向中日相反,令 下半中文作「龴」日文多作「マ」,道 的走之底中文两点、日文常作一点。
4 · 字形由谁决定
码点不带字形,浏览器靠两条路决定画哪一种。其一是字体回退看 lang:正文用的西文字体没有 CJK 字形,遇到汉字要回退到系统字体,回退时参考元素的 lang 选「该语言的」那套。其二是一套字体内部按 locl 切换:支持多语言的泛 CJK 字体(Source Han Sans、Noto Sans CJK)用 OpenType 的
localized forms 特性,按 lang 为同一个码点切换字形变体,一套字体就能画出中日韩三态。
警示 · 网页若不标 lang,在中文环境下显示日文文本,汉字会被画成中文字形。对日本读者那就是「字写错了」,尽管码点完全正确。本页整页是 lang="zh-CN",所以正文里没标 lang 的汉字默认走中文字形;上面两个 lab 能显出日韩字形,靠的是逐元素标了
lang。
5 · 繁简与异体字
Han 统一是「同码点、不同字形」,它有个天然的反面:謝(U+8B1D)与 谢(U+8C22)是两个码点,却是同一个词的繁简两种写法。这次连归一化都不合并它们,四种形式跑下来 謝 仍是 謝。
归一化故意不管这件事,因为繁简关系不满足等价的前提:它有损、依赖词义,还常常一对多。发 一个简体对应 發(发展)与 髮(头发)两个繁体,干 对应 干 / 乾 / 幹。若让 NFKC 把 谢 折成繁体,就会在别处把
发 折错。真正记录这层关系的是 Unihan 数据库的异体字字段:kSimplifiedVariant、kTraditionalVariant,此外还有 kSemanticVariant、kZVariant、kSpoofingVariant。JS 原生不做繁简,\p{…}、Intl 与
String.normalize 都不碰,必须引库。
6 · 词组级转换
单字表给 发 列出两个候选却选不出该用哪个:字符级映射看不到上下文。真实转换走词组级词典加最大匹配:先认出「头发」「发展」这样的词,再整词替换,同一个 发 于是在不同词里转成不同的繁体字。含地区用词的方向还会把 软件 换成 軟體、出租车 换成
計程車,这时转换前后字数都可能变,更不可能用字符映射表完成。
建议 · 三层别混。同一个抽象字的多种码点写法,拍平靠归一化;同一个码点的多种字形,交给字体与 lang;不同码点表示同一个词,既不在码点也不在字形里,要查 Unihan 加词典。落到工程上是三件事:给内容标对 lang,整页定基调、混排处用
<span lang="ja"> 局部覆盖;字体栈按 locale 提供对应字体,或选支持 locl 的泛 CJK 字体;别指望从字符本身区分语言,一个「刃」是中文还是日文的,字符里没有这个信息。
7 · 参考文献
- Unicode. The Unicode Standard, Chapter 18: East Asia. Han 统一的规则出处:CJK 统一表意文字的收录原则与 Source Separation Rule。unicode.org
- Unicode. UAX #38: Unicode Han Database (Unihan). 异体字字段的定义:
kSimplifiedVariant、kTraditionalVariant、kSemanticVariant等。unicode.org - Iguchi, K. Your Code Displays Japanese Wrong. 不标
lang导致日文被渲染成中文字形的现象与截图对照,本页第 4 节的由来。heistak.github.io - BYVoid. OpenCC. 上游的词组级繁简转换库与词典数据。opencc.byvoid.com
- nk2028. opencc-js. OpenCC 的浏览器版移植,本页转换 lab 直接调用它。github.com