波兰字母 S 消失的奇案The curious case of the disappearing Polish S
这是一个长达三十年才被发现的键盘输入法 Bug,导致了波兰语中特定字符的消失。文章追溯了该编码错误的历史根源,探讨了早期软硬件设计中对特定语言字符集处理的疏漏。通过分析这个长期潜伏的边缘案例,揭示了国际化输入和底层字符编码标准在复杂系统演进中产生的冲突。作者最终指出,这种看似微不足道的字符丢失问题,实际上是计算机历史遗留系统中难以根除的结构性缺陷。
Marcin Wichary
Marcin Wichary
2015年2月2日 / 1,800字
最初发表于 Medium Engineering
一个酝酿了三十年的键盘 Bug
几周前,有人在 Medium 向我们报告了这样一个问题:
“我刚用波兰语开始写一篇文章。我能打出除了 Ś 之外的每一个字母。当我按下 Ś 键时,这个字母就是不出现。这种情况只在 Medium 上发生。”
这很奇怪。我们并没有对任何语言进行任何特殊的处理,退一步讲,就算有……在 32 个波兰语字符中,为什么偏偏只有这个随机的字符会出问题?
事实证明,这并非偶然。这是一个关于跨越数十年(甚至数百年)的四个偶然因素是如何凑在一起,引发了最离奇的 Bug,以及我们是如何修复它的故事。
因素 1/4:波兰语
波兰语是第二大最常用的斯拉夫语系语言,仅次于俄语,略领先于乌克兰语。然而,与这两种语言不同的是,波兰语与德语或法语等西欧语言类似,使用的是英语/拉丁字母表,并带有一些定制字符。
这是基础的英语字母表,与经典的拉丁/罗马字母表基本相同:
原始的波兰语单词从不包含 Q、V 或 X,尽管我们会保留它们用于拉丁语和其他外来词:
然而,作为这三个字母的替代,波兰语以拉丁字符为基础增加了九个额外的带变音符号的字母,它们都相对常用:
从 20 世纪初开始,打字机需要容纳这额外的 9 个字母。如果你把一台美国打字机和一台波兰打字机进行对比:
……看看键盘的右侧,你可以看到两个带变音符号的字母——Ł 和 Ż——升级成了独立的按键,其余的则与数字共享按键。(在打字机时代,打字员通常会被建议通过打出一个拉丁字母、退格,然后再覆盖一个重音符号来“模拟”出剩下七个字母的大写版本。这在打字机时代并不罕见。)
为了给额外的字母腾出空间,打字机不得不舍弃一些标点符号,最明显的是分号(用逗号+退格+冒号代替)和括号(在日常使用中被斜杠取代)。
因素 2/4:共产主义
对于对 20 世纪 80 年代早期个人电脑感兴趣的人来说,波兰的共产主义意味着两件事:
我在波兰长大。我的第一台电脑——辉煌的 Atari 800XL——是 1979 年的原创技术,在 1983 年重新包装。我在 1986 年买到了它的二手货。
这并非个例。在铁幕的那一侧,技术的传播是滞后的;大多数计算机都是从西方进口的。禁止商业进口意味着在很长一段时间里,没有任何商业实体能够为计算机在波兰的使用做好准备。外国计算机运来时带有原始的说明书、未翻译的软件,以及像这样的美式键盘:
当法国、德国和其他国家早期的个人电脑配备了定制键盘,其布局与之前的打字机高度相似时……
……在波兰,我们不得不寻找另一种方法来输入我们语言中独特的 9 个额外变音符号。
我们这些额外的字符看起来可能非常像对应的拉丁字母,并且在字母分布中仅占 8% 左右(玩拼字游戏时你会讨厌它们),但它们很重要。你不能随意替换它们。看看这两个相似的短语:
完全可以互换,对吧?嗯,并非如此:
这样的例子还有很多。碰巧,在早期使用个人电脑的日子里,我甚至很高兴我的全名 Marcin Kazimierz Wichary 不包含任何变音符号,省去了不少麻烦。
不过,肯定有什么办法能解决这个问题吧?让我们回到键盘上:
我们无法以任何方式修改它,因为那需要改动硬件,但我们仍然可以尝试找到一个巧妙的解决方案。键盘上有两个修饰键——Ctrl(即今天的 Caps Lock 键所在的位置)和 Alt。甚至在 CtrlC 和 CtrlV 成为复制和粘贴的典型快捷键之前,Ctrl 就已经被用作常见的快捷键了。但 Alt 相对少见。因此,一个事实上的标准诞生了,将我们的 8 个变音符号分配给对应的拉丁字母,还有一个分配给附近的按键:
人们开始将旧的布局称为“打字员布局”,将这项新发明称为“程序员布局”,这可能是因为早期的 PC 用户主要是程序员,或者是因为它保留了编程中经常使用的所有标点符号。
这种新布局简直是一场人体工程学的噩梦——看看有多少字母非常靠近左侧孤零零的 Alt 键,而且需要用同一只手来按——但它易于理解,不需要任何昂贵的硬件修改,甚至不需要廉价的修改(例如贴纸)。它因此被保留了下来。其他几个周边国家——罗马尼亚、当时的捷克斯洛伐克——也想出了类似的方案。
这种设置非常成功,以至于即使在十年后,当正规的打字员键盘开始出现时,也几乎没有人愿意换用它们,这反映了大约 80 年前不那么理想的 QWERTY 布局的崛起。
要素 3/4:旧习难改
如今很常见的自动保存功能,在过去需要等待合适的时机。特别是在 20 世纪 80 年代甚至 90 年代,保存文档是一个漫长的过程(启动软驱并向磁盘写入数据需要一些时间),它会慢慢磨损你使用的任何存储介质,而且有时会极大地占用 CPU,以至于无法用它来做任何其他事情。
手动保存就像今天的备份一样:是一个你需要为了自己好而去学习的习惯。那些不走运的人只能通过惨痛的教训来明白这一点,他们在一台经常残酷崩溃的电脑上写了几个小时,结果却发现自己忘记保存工作内容了。
我就是其中之一。我们都学会了在喘口气的时候按下 CommandS 或 CtrlS。有时是每写完一段按一次。通常是每写完一句。后来,甚至是每隔一个单词。CtrlS 成为了深植于人们肌肉记忆中的一次按键,这种习惯就像害怕面对空白页一样,成为了写作不可或缺的一部分。
后来,这个习惯反而给他们带来了麻烦。如果你在任何基于 Web 的编辑器中写作,按下保存组合键后,默认弹出的会是一个浏览器窗口——给你一个毫无用处的选项来保存当前网站的 HTML 代码,而且通常还会伴随一个缓慢、烦人的动画效果。
很久以前,Medium 也是如此:
然而,在某个时候,我们在编辑器中添加了一小段代码,让保存对话框消失:
if ((e.metaKey || e.ctrlKey) && e.keyCode === goog.events.KeyCodes.S) {
this._editors.save()
e.preventDefault()
}这段代码的意思是:如果碰巧在按下 S 键的同时按下了 Command 键(metaKey,Macintosh 使用)或 Ctrl 键(Windows 或 Linux PC 使用),首先:提示我们的编辑器保存当前正在做的事情(即使我们很快就会自动保存),其次:阻止通常会发生的其他任何事情……在这个例子中,也就是那个烦人的浏览器保存对话框。
感觉这样做是对的。(如果你愿意,你仍然可以从菜单中调出保存对话框。)
如果你还记得开头提到的那个 Bug 报告,这现在应该会在你脑海中警铃大作:
“我刚用波兰语开始写一篇文章。我可以输入每个字母,除了 Ś。当我按下 Ś 对应的按键时,这个字母就是出不来。这种情况只在 Medium 上发生。”
不过,这有点说不通。Medium 屏蔽了 CommandS 和 CtrlS,但你输入 Ś 时按的是…… AltS。
要让这两个世界发生碰撞,我们只需要再加一样东西。
原料 4/4:Microsoft Windows
Windows 3.x 和 95 都拥有出色的键盘支持。菜单项和对话框中的控件不仅可以通过鼠标轻松访问……还可以通过按下 Alt 和任意带下划线的字母来实现更快的访问:
微软 Windows 的大部分 UI 操作都可以转换为一连串的键盘按键,这非常强大——甚至 Mac 至今仍能从中借鉴。然而在波兰,Alt 键早已被普遍用于输入额外的变音符号。这就产生了冲突。幸运的是,到那时键盘已经进化出了额外的修饰键,包括空格键另一侧的第二个 Alt 键。
在欧洲许多定制键盘上,这个键通常被称为 Alt Gr,但波兰主要进口的仍然是英文键盘。
那么,如果我们保留左 Alt 键用于 Windows 快捷键,而使用右 Alt 键来输入波兰语变音符号会怎样呢?这就能解决所有问题了(尽管通过两个修饰键来改善人体工程学的短暂胜利再次被抵消了……这次是由于单手按 Right AltO、Right AltL 和 Right AltN 会让你的手指处于一种不舒服的姿势,这可是字面意义上的)。
但是,对于只有一个 Alt 键的老式键盘,也需要能够使用右 Alt 键的功能,因此微软在 Windows 内部将右 Alt 键映射为了一个很少使用的组合键,即同时按下 Ctrl 和 Alt。
这意味着,从系统的角度来看,上述所有快捷键看起来都是这样的:
这张图里有些地方让人觉得莫名地不安。那个 CtrlAltS 现在看起来是不是非常眼熟了?事实上,它与我们为了改善保存功能而开始拦截的 CtrlS 惊人地相似。
修复方案
把所有这些结合起来,出现这个 Bug 的原因就显而易见了:
一旦我想通了这一点,修复补丁就很简单了。我们不需要盲目且贪婪地拦截所有的 CtrlS,而是可以只在没有按下 Alt 键的情况下才拦截 CtrlS:
if ((e.metaKey || (e.ctrlKey && !e.altKey)) && e.keyCode === goog.events.KeyCodes.S) {
this._editors.save()
e.preventDefault()
}我们上周修复了这个问题,这并没有费多少功夫。在看到提交上来的 Medium Bug 报告后,回想起之前添加拦截 CtrlS 功能的经历,我没费多大劲就想明白了。
但我碰巧是波兰人,我经历了上述的一切——在我妈妈的打字机上学习盲打,拥有配备美式键盘的早期 PC,首先为左 Alt 键重塑我的肌肉记忆,其次才是右 Alt 键……并且在同样的肌肉记忆中,早早地植入了 CtrlS,然后在我改用 Mac 时又将其替换为 CommandS。
Much has changed in Poland since the 1980s. In 1989, Communism fell. Computers are now imported legally by individuals and companies alike. Today’s Windows and Mac machines in Poland are bought new, fully support Polish, and the operating systems themselves are properly localized. If you open up system preferences, though, you will still see the programmer’s layout there, and it’s still the most commonly used of the two.
The few lines of code above might be, to me, one of the most curious in Medium’s codebase, the result of an arbitrary set of circumstances… today copiously commented so that people coming after me understand the one opaque conditional statement.
Those lines are also part of a much larger story of hegemony of American computing, where so much still evolves around conventions surrounding the relatively simple English language with its 26 unaccented letters. You can’t help but think Polish language continues fighting for scraps, allowed only to move from one xeroxed derivative of QWERTY to another – and many other languages are even less lucky, their writing systems so much further away from English.
This was a tiny change, but I’m grateful for people working diligently and spending so many more hours every day so that people speaking these languages can use software well, without encountering English-tinted assumptions, decisions, and exceptions.
需要完整排版与评论请前往来源站点阅读。