第 1 讲 / 共 10 讲

Unicode 的历史:计算机如何学会保存全世界的文字

把一段中文、一个带重音的姓名和一枚表情放进同一条消息,如今几乎不需要思考编码。可这种平常,建立在几十年的标准协作之上。Unicode 的历史值得了解,因为今天的乱码、缺字和字符串长度问题,往往仍然带着早期技术选择的痕迹。理解这些选择,也能帮助我们判断:一段文字出了问题,究竟该检查文件、程序,还是字体。

Copy2Paste约 11 分钟阅读

最初的问题:数字有了,解释数字的办法却不统一

计算机保存的是数字。要让数字表示文字,发送方和接收方必须使用共同约定。可以设想两本不同的号码簿:同一个号码,在第一本里对应某个字母,在第二本里却对应另一个符号。文件并没有丢掉任何数字,读出来的文字仍然可能完全错误。字符编码处理的正是这种对应关系。

早期软件通常围绕特定市场和设备设计字符集。ASCII 为英语字母、数字、标点和控制功能提供了共同基础,但它不是覆盖世界书写系统的方案。后来的地区编码分别解决了自己的实际需要,中文用户熟悉的不同编码环境,也属于这段历史。对单一环境来说可用,对跨语言文件交换来说却意味着更多前提。

这类问题很容易被误诊为“换一个字体就好”。字体负责画出收到的字符,编码负责说明字节代表什么。如果接收方已经把原来的字节解释成别的字符,换字体只会把错误结果画得更清楚。把识别文字和绘制文字分开,是阅读整段历史的起点。

统一编号带来的改变,不只是少几种乱码

假设一家出版社保存中英文书目,作者姓名还可能包含欧洲语言的重音字母。如果每条记录都要附带一套解释规则,那么搜索、导出和复制都必须不断判断规则是否改变。书名字段与作者字段合并时,还可能遇到两种编码无法直接共存的问题。增加一个新市场,就要再增加一批转换和测试工作。

统一的字符编号体系提供了另一种组织方式:先在共同的空间里识别字符,再选择适合传输和存储的编码形式。这里的“统一”不是要求所有人使用同一种语言,也不是把不同字母都改画成同一种样子,而是减少文字在系统之间交接时必须携带的隐含约定。

因此,Unicode 的价值不能只用字符总数衡量。对于产品团队,更直接的变化是姓名可以原样保存,多语言评论可以出现在一个字段里,数据导出不必为每种语言另造一种格式。这些工作仍需正确实现,但共同基础让它们成为同一道工程问题,而不是一组互不相通的地方方案。

从1987 年的讨论,到1991 年的正式版本

Unicode 官方历史将项目起点放在1987 年末,参与早期讨论的工程师来自 Apple 和 Xerox。1988 年的 Unicode 88 文稿记录了初期构想。之后参与者扩大,字符收集、已有标准映射和公开审阅逐步推进。Unicode 联盟于1991 年 1 月成立,第一版标准的第一卷在同年 10 月出版。

这些时间点说明,它不是某家公司突然交付的一套字体,也不是某位程序员独自整理的符号清单。实际工作包含大量看似琐碎的核对:已有字符是否遗漏,旧系统里不同的项目能否往返转换,两个来源描述的是否是同一字符。若省略这些步骤,再优雅的新设计也很难接住已经存在的数据。

读技术史时,还要区别正式版本日期、数据发布日期和纸质出版日期。不同材料写出不同月份,不一定有人记错,也可能在指向不同事件。查原始时间表,比拿一个年份为整段发展过程画句号更可靠。

与国际标准协作:共同编号,还需要共同处理规则

1991 年,负责 ISO/IEC 10646 的工作组与 Unicode 方面决定协调建立通用的多语言文字编码标准。今天两者的字符及编码位置保持同步,而 Unicode 还提供大量字符属性和文字处理规则。对普通用户,这些组织名称可以不记;对实现者,重要的是共同编号背后还有可执行的约定。

举一个简单的设计问题:系统收到一个字母以后,可能还需要判断它的大小写关系,决定文字方向,或处理后面附着的记号。一个只有“编号和名称”的表格,无法独立回答所有这些问题。实际文本处理要依靠相互配合的数据与算法,编码表只是其中基础的一部分。

这也解释了为什么“支持 Unicode”必须说得具体。软件能够无损保存某个字符,并不证明它能够正确搜索、分词或排版;数据库接收了字节,也不证明页面用了合适的字体。测试时把这些能力拆开,比给整个产品贴一个支持标签更有用。

16 位设想留下了什么,又如何被突破

早期 Unicode 与16 位编码紧密相关,因此“一个 Unicode 字符占两个字节”的说法长期流传。但从1996 年的 Unicode 2.0 起,标准的码点范围扩展到 U+0000 至 U+10FFFF。现代 Unicode 不能再用固定16 位概括。常见的 UTF-8、UTF-16 和 UTF-32,是同一字符体系的不同表示办法。

这种历史对今天仍有直接影响。有些程序接口以16 位码元为单位索引字符串,于是常见汉字和许多英文字母各占一个单位,某些表情或扩展汉字却占两个。问题并不在于表情“太新所以不规范”,而在于代码使用了存储单位,却把它叫作用户看到的一个字。

升级思路也不应只是把变量改大。即使换成每个码点占一个单位的表示,一个视觉上的完整符号仍可能包含多个码点。历史促成了分层设计,而不是最终发现某个足够大的整数就能包办文字。下一篇会展开这些编码形式各自解决的问题。

汉字统一为何经常被误解

中文读者谈到 Unicode,常会关心中日韩统一表意文字。这里的统一针对字符身份,并不要求中文、日文和韩文使用同一语言习惯,也不承诺每个地区都画出完全一致的字形。同一码点的显示,可以受字体和语言环境影响。汉字的地区字形差异因此不能简单归结为“编码把字写错了”。

可以把实际排查分成两步:先检查复制出的码点是否是想要的字符,再检查页面语言和字体是否适合目标读者。把截图发给别人时,看到的是一次具体渲染;把文字复制给别人时,传递的是字符序列。两种交流方式保留的信息不同,比较结果也可能不同。

这对本地化写作尤其重要。中文文章需要自然的术语、标点和字体选择,英文版则需要符合英文读者习惯的叙述。统一编码提供的是共同底座,不会替作者完成语言编辑。一个网站支持多个文字系统,与它真正尊重不同读者的阅读习惯,是需要分别做好的两件事。

为何有些历史包袱会一直留下来

Unicode 的稳定性政策规定,自相应承诺适用的版本起,已编码字符不会因为后来发现更漂亮的布局而被移动或删除。字符名称也具有稳定性;遇到名称错误,可以通过别名等方式补充说明。这样做让多年以前保存的文本在新系统中仍可被识别,同时也意味着标准不能随意重新整理历史。

设想一份长期保存的合同引用了某个字符。若升级标准就会让同一编号改指另一个字符,档案、签名和数据库索引都要跟着重写。对长期交换格式而言,保留不够理想但明确的旧选择,往往比每隔几年追求一次整洁更值得。这是兼容性成本,也是基础设施取得信任的条件。

稳定并不等于所有数据和算法永远不变。新字符会加入,某些属性或处理规则也会修订。工程上应记录所用版本,尤其是把搜索、分段结果作为持久数据时。既不能认为升级会改变所有旧文字,也不能认为只要叫 Unicode,所有软件版本就一定产生相同结果。

表情让更新变得可见,文字本身仍是核心

手机用户最容易注意到新表情,但 Unicode 的工作范围还包括现代与历史文字、技术符号以及其他文字表达所需字符。以本篇发布时已公布的 Unicode 18.0 为例,查看官方版本页,比只读一张新表情拼图更能看见完整更新范围。一个版本的意义,不该只看它是否增加了自己常用的图案。

对于已有输入法和字体的人,一次新增可能只是列表多了一行;对于需要记录姓名、整理文献或书写某种文字的人,能否使用标准字符却可能影响一整套工作。把小众使用当成次要问题,会忽略通用文字系统最基本的目标:不同群体的数据都应有机会进入可交换的技术体系。

同时,标准收录只是软件支持链的一个阶段。输入法、字体、操作系统、浏览器和应用更新各有节奏。看到新字符的方框时,应检查目标设备是否具备显示能力,不能直接断定复制失败。原样保存的字符序列,可能在另一台有合适字体的设备上正常显示。

文字能够留下来,还需要可追溯的数据

今天的 Unicode 不只有供人阅读的标准正文,还有供软件使用的 Unicode 字符数据库。实现者可以取得字符属性和相关数据,按照规则构建功能。读者不必亲手处理这些文件,但应知道:浏览器知道怎样分类一个字符,并不是靠观察它的图片,而是依靠随软件交付的数据和算法。

这为保存数字资料提供了一个实际提醒。整理旧文件时,除了保存最后能读通的文本,还应记录来源编码、转换步骤和出现过的异常。若只留下“修好了”的新文件,后人很难判断一个问号本来就在原文里,还是导入时丢失信息的结果。标准让长期保存成为可能,工作流程则决定这种可能是否兑现。

同样,一篇介绍 Unicode 的文章应把版本相关事实与长期稳定的概念分开。发布时间表可以核查,当前字符数量需要标注版本,作者自创的例子则应能复现。读者由此能分辨哪些内容会随着新版本更新,哪些基本关系仍然成立,也能在遇到矛盾时回到原始资料,而不是在不同教程之间反复猜测。

用一个复制场景,把历史重新串起来

现在回到一条包含中文、重音姓名和表情的消息。输入时,键盘或输入法产生字符序列;程序在内部保存字符串;网络将它转换为约定的字节;接收端解码后,再由字体和排版系统呈现。每一层都有自己的职责。Unicode 让它们能围绕同一组字符身份协作,却没有让这些层次消失。

因此,遇到异常时可以先保留原文,再在 Unicode 检查器中查看码点。码点符合预期但出现方框,优先查显示支持;码点已经变成别的文字,回查解码和导入;仅长度限制不对,则检查程序到底在数码元、码点还是字素簇。这样的顺序能减少反复换字体、重粘贴却找不到原因的情况。

学习历史的收益就在这里:我们不必记住每一次会议,也能理解为什么现代文字系统保留多种表示、为什么某些接口带着旧时代的边界,以及为什么全球通用与本地习惯必须同时照顾。下一次复制一个符号时,值得确认的不只是“看起来像不像”,还有它在传递过程中是否仍是原来的文字。

参考资料

  1. UTR #17: Unicode Character Encoding Model ↗
  2. Unicode FAQ: Basic Questions ↗
  3. Unicode 历史:Summary Narrative ↗
  4. Unicode Release and Publication Dates ↗
  5. Unicode and ISO/IEC 10646 ↗
  6. Unicode FAQ: UTF-8, UTF-16, UTF-32 and BOM ↗
  7. ECMAScript: The String Type ↗
  8. Unicode FAQ: Chinese and Japanese ↗
  9. Unicode Character Encoding Stability Policies ↗
  10. The Unicode Standard, Version 18.0 ↗
  11. UAX #44: Unicode Character Database ↗