给汉字注音:读音不在码点里
Han 统一 讲的是一个码点不带字形,长什么样交给字体。本页讲它的孪生事实:一个码点也不带读音。'重'.codePointAt(0) 只得到编号 U+91CD,这个数字里既没有笔画,也没有它读 zhòng 还是
chóng。读音与字形一样记在码点之外:Unihan 的 kMandarin 与 kHanyuPinyin 字段、CLDR 的 Han-Latin 转写表。而且读音比字形更麻烦,同一个码点常有多个读音,选哪个取决于词。
1 · 给一段文本注音
HTML 原生的 <ruby> 负责排版:基字写在 <ruby> 里,注音放进 <rt>,浏览器把注音排在基字上方,不支持时退化成括注。算出每个字读什么则是库的事,本页用 pinyin-pro。两件事分得很干净——排版不依赖任何库,注音结果也不关心怎么渲染。
2 · 读音取决于词
单看一个码点只知道它可能读哪几个音,选不出该用哪个,这与 繁简转换 里单字表给 发 列出两个候选却停在那儿是同一回事。定音的是上下文:重 在「重要」里读 zhòng、在「重复」里读 chóng,行 在「银行」里读
háng、在「行走」里读 xíng。把 重 无脑映射到第一个候选,就会把「重复」读成 zhòng fù。
pinyin-pro 的做法是内置词典加最大匹配分词,先认出「重复」「重要」这样的词,再为其中的字定音。所以注音与繁简转换属于同一类问题:查词典级、依赖分词,不是逐码点的无歧义查表。
3 · 音节的三段结构
拼音音节有固定结构:声母(开头的辅音)、韵母(余下的元音收尾)与声调。声母可以为空,爱 的音节 ài 就是零声母;声调为 0 记作轻声,不标调号。
4 · 注音串的归一化
声调标在韵母的主元音上,nǐ 的 ǐ、nǚ 的 ǚ 都是 归一化 那页的老熟人:它们在 NFC 下多是单个预组合码点,NFD 下会拆成基础元音加组合声调记号。于是注音串的长度随归一化形态而变——'nǚ'.length 是 2,'nǚ'.normalize('NFD').length
是 4,因为 ǚ(U+01DA)会拆成 u 加分音符加抑扬符三个码点。比较或存储拼音串前先归一,否则同一个 nǚ 会因写法不同而判不等。
建议 · 码点之外的三层信息到这一页收齐了:字形交给字体与 lang,读音查 Unihan 与 CLDR 再靠分词定夺,繁简与异体关系查 Unihan 变体字段加词典。一句话,码点定的是「哪个抽象字」,字形、读音与词义对应统统是码点之外的数据。
5 · 参考文献
- Unicode. UAX #38: Unicode Han Database (Unihan).
kMandarin与kHanyuPinyin等读音字段的定义与数据格式。unicode.org - Unicode. CLDR: common/transforms.
Han-Latin.xml即注音转写表本身,注音的另一份权威数据。github.com -
MDN.
<ruby>. 注音排版的原生标记:<ruby>、<rt>与<rp>的语义与回退行为。developer.mozilla.org - pinyin-pro. 文档. 本页所用的注音库:词典分词、声调写法与音节拆分接口。pinyin-pro.cn