Hyaika Blog

Penguin is all you need

设计

那个不存在的单词「an unicorn」,和 129 个例外

那个不存在的单词「an unicorn」,和 129 个例外

那个不存在的单词「an unicorn」,和 129 个例外

目录

  • 一个成年人才会注意到的英语问题
  • 32455 个词,129 个例外
  • y 和 w:被开除出元音队伍的叛徒
  • h 的失踪案:从 heir 到 honor
  • The Letter Name Trap:26 个字母自己也要选 a/an
  • an apron 的诞生:一场流传几百年的耳朵误会
  • 现场验证:我把发音词典整本翻了一遍
  • 一个循环,和一套手写规则

一个成年人才会注意到的英语问题

英语里有个规则,小学老师教的:a 用在辅音开头的词前面,an 用在元音开头的词前面。a catan apple。就这么简单。

然后你遇到了 unicorn

unicorn 以元音字母 u 开头,按规则应该是 an unicorn——但没有任何一个母语者会说 an unicorn。我们都说 a unicorn,因为 unicorn 虽然起来是元音开头,起来却是辅音开头:/junɪkɔrn/。u 在单词里读成了 "yoo",y 是辅音音。

所以真正的规则不是「看第一个字母」,而是「听第一个」。

问题是:这个「听音」的规则,到底有多准?用「看字母」的规则去碰运气,会错多少次?Red Blob Games 的作者 Amit Patel 花了整整一天去查发音词典,最后发现:32455 个英文单词里,只有 129 个是例外。

129 个,一张纸就能列完。这是整篇故事里最让我意外的数字——我以为会错一大片,结果差点就是 0。

32455 个词,129 个例外

Amit 干了一件程序员才会干的事:把卡内基梅隆大学的发音词典(cmudict)整本下载下来,然后写代码判断「第一个字母是元音吗」和「第一个音是元音吗」是否一致。

结果出乎意料地好。**32455 个单词(排除了专有名词、单字母、缩写、标点后),按「首字母规则」判断,只有 129 个词会翻车。**准确率 99.6%。

这 129 个例外不是随机散布的,它们整整齐齐地聚成了几个家族:

家族 代表词 为什么例外
eu- 读成 /ju/ eucalyptus, eunuch, eulogy e 开头但读 yoo
u- 读成 /ju/ unicorn, university, urology u 开头但读 yoo
h- 不发音 hour, heir, honest, honor h 开头但元音开头
o- 读成 /w/ one, once, oneness o 开头但读 wuh

看到规律了吗?大半的例外都是同一个音在捣乱:/j/。

前两字母判定树:蓝=恒元音,黑=恒辅音,红=有时元音有时辅音
eucalyptus 和 unicorn 表面差很远,但开头都是那个「yoo」音——一个由字母 y 或 u 假装发出来的辅音。英语把 /j/ 归为辅音,于是所有以 yoo 开头的词,哪怕写作 eu,都得用 a

y 和 w:被开除出元音队伍的叛徒

英语的元音字母五个:a, e, i, o, u。但发音上真正在「元音/辅音」之间摇摆的,是 y 和 w。

yyesyard 里是辅音,在 mythgym 里是元音。wwater 里是辅音……可 oneonce 开头的音其实就是 /w/,所以它们写作 o 开头,却读作 w 开头——于是 one 按首字母规则会被判成 an one,大错特错。

最讽刺的例子是 yttrium(钇,化学元素)。它是 129 个例外里唯一一个不属于任何家族的孤儿:以辅音字母 y 开头,却读作 /ˈɪtriəm/,是元音开头,所以它要 an yttrium。一个辅音字母,读出了元音,独自一人站在例外列表的角落。

英语拼写和发音之间的裂缝,在这个单词上裂到了最大。

h 的失踪案:从 heir 到 honor

另一大族是「h 不发音」。

hour 的 h 不发音,所以是 an hourheirhonesthonorhonoraryhonorific 全都一样,h 是哑巴,元音是首领。herb 在美国英语里 h 也不发音(an herb),但在英国英语里 h 发音(a herb)——同一个词,两个国家,两种 a/an。

Amit 的规则代码里有个有趣的注释:他没处理古老的 an hospital 例外。很久以前,英语有些方言不发音 h,所以人们说 an hospital,这个用法写进了书和报纸。后来发音变化,h 恢复了声音,an hospital 就变成了一条例外中的例外——正在慢慢消亡。语言是活的,规则列表会过期。

需要看几个字母才能决定 a/an:例外往往集中在少数分支

The Letter Name Trap:26 个字母自己也要选 a/an

最让我会心一笑的,是 Amit 提到的第二个场景:单个字母的名词,也要选 a/an。

你要是念一个密码 FBI,你会说 an FBI agent 还是 a FBI agent?答案是 an,因为 F 这个字母的名字读作 /ɛf/,是元音开头。而 NASA 读作 /ˈnæsə/,辅音开头,所以要 a NASA mission

我把 26 个字母按它们自己的发音过了一遍,得出:

an 的 12 个:A, E, F, H, I, L, M, N, O, R, S, X
a 的 14 个:B, C, D, G, J, K, P, Q, T, U, V, W, Y, Z

h 读作「aitch」元音开头所以是 an H,u 读作「you」辅音开头所以是 a U——读「you」,然后发现这个字母本身又是那个 /j/ 叛徒在捣乱。整个系统,处处都是同一个幽灵。

26 个字母按字母名发音的 a/an 分布:12 个用 an,14 个用 a

an apron 的诞生:一场流传几百年的耳朵误会

129 个例外是「现在」的规则清单。但英语的历史里,有个更妙的机制在反向运作:重分析(rebracketing)。

维基百科的经典例子:15 世纪的人说 a napron(围裙)。因为 napron 以辅音 n 开头,所以前面是 a。但这个词太常被听见了,人们把 a napron 听成了 an apron——反正都差不多——然后干脆把那个 n 从围裙上撕了下来,安到了冠词上。几代人之后,apron 变成了标准拼写,napron 反而消失了。

同样的故事还发生在 a newt(蝾螈,来自 an ewt)、an adder(蝰蛇,来自 a nadder)、an orange(橙子,西班牙语里还叫 naranja,保留了那个 n)身上。

换句话说:今天我们在背的 129 个例外,有一部分是几百年前「an 和 a 边界上的幻觉」留下来的化石。 单词的拼写被错误切分重塑,冠词的那个 n 像个流浪汉一样,从这个词搬到那个词。你现在看到 an apron,其实是听到的 a napron

现场验证:我把发音词典整本翻了一遍

说这么多,不如自己动手。我下载了同一份 cmudict 发音词典,把 Amit 的算法重写了一遍,然后亲自踩了他踩过的所有坑。

第一坑:cmudict 的元音音标带数字标号。 AA1 是元音,但 AA 也是。我第一版代码只检查了 ph[0] 是否在元音表里,结果把所有带重音数字的元音全部误判成辅音——跑出来「谜之 558 个例外」。和第二坑正好是同一堵墙的两面。

第二坑:全量词典 vs 过滤后的词典。 我用完整 cmudict 跑首字母规则,得到 17395 个「不匹配」——看起来天塌了。但实际上绝大多数是专有名词(fbihtmlherbertnvidia)和缩写,它们本来就不属于「普通英文单词」。Amit 用 BSD 词典交集过滤后,不匹配立刻缩到 275 个。

第三坑:他的 129 个例外,我逐个对了一遍。 我把 Amit 文章里列的那 129 个词,全部拿去和我的 cmudict 比对——每一个都确实是「字母元音 ≠ 读音元音」的真例外。一个不多,一个不少。113 个在我的词典交集里找到了,全部验证通过。

第四验证:他的手写规则有多准? 我把 Amit 那 20 行 starts_with_vowel 手写规则原样实现,跑在我过滤后的词典上,剩下 83 个词还是错的——但看列表,全是 fbimitunesconvidia 这类缩写/专名/外来词,正是他主动排除的类别。他的规则在他定义的范围内是完美的。

整个验证链条走完,我得出一个确定的结论:英语的 a/an 规则,99.6% 的时候「看字母」就够用;但那 0.4% 的例外,是英语拼写和发音三百年恩怨的缩影。

一个循环,和一套手写规则

最后说一个让我愣了几秒的细节。

Amit 把 129 个例外写成了 20 行硬编码的手写规则:if word.startswith("eu"): return Falseif word.startswith("hour"): return True……他承认没能找到比「手写 if-else」更优雅的算法,尽管他试过把问题规约为 DFA 最小化——一个计算机科学里已经研究了 60 年的问题。

所以这是整件事最妙的闭环:英语的 a/an 选择,本质上是一个「有限状态机最小化」问题;而人类已经用自然语言把它优化了几百年。 计算机科学家想用 DFA 最小化算法来解决它,最后发现最实用的解是 20 行人类手写的规则——这 20 行规则,就是几百万英语母语者脑子里那套「听起来顺不顺」的近似实现。

规则可以写进代码,但规则的来历(为什么要为 hour 破例?为什么 yttrium 是孤儿?)只能靠历史来讲。a/an 这个小到不能再小的英语功能词,底下埋着一整部音韵学、词源学和拼写改革的历史。下次你犹豫要不要说 an unicorn 的时候,记住:你是在和一个 300 年的语言系统搏斗,而它已经赢了。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论