从 ASCII 到 UTF-8:一部字符集的发展史 从 ASCII 到 UTF-8一部字符集的发展史当你在键盘上按下一个A或者输入一个你计算机究竟是如何知道它们是什么字符的今天我们已经习惯了 UTF-8、Unicode 等名词但这些标准并不是凭空出现的而是计算机工业几十年发展的结果。本文将按照时间顺序完整介绍字符集的发展历史、出现背景、解决的问题以及为什么最终走向了 Unicode 和 UTF-8。一、字符编码为什么会出现计算机本质上只认识两种状态0 1CPU、内存、硬盘里面都只有二进制。那么问题来了。当用户按下键盘上的A时计算机应该存储什么存成01000001还是00110110还是别的如果没有统一标准不同厂商可以随便定义。例如IBM 规定A 00100001另一家公司规定A 11001010那么一台 IBM 计算机保存的文件另一台计算机打开以后看到的可能就不是 A而是一个完全不同的字符。这就是早期计算机面临的第一个问题不同设备之间无法交换文本。于是人们开始思考能不能给每一个字符分配一个唯一的编号这就是字符编码诞生的原因。二、ASCII计算机历史上的第一个统一字符集1963 年美国标准协会ANSI 的前身制定了 ASCIIAmerican Standard Code for Information Interchange。它的目标非常简单所有英文字符都使用统一的数字表示。例如字符十进制十六进制A650x41B660x42a970x610480x30空格320x20以后无论是哪家公司生产的计算机只要看到数字 65就知道这是字符 A。ASCII 第一次实现了不同计算机之间的文本互通。三、为什么 ASCII 只有 128 个字符今天看来128 个字符非常少。但在 1960 年代这已经是一个非常合理的设计。当时的计算机内存极其昂贵CPU 运算能力有限网络几乎不存在工程师统计了一下英语需要26 个大写字母26 个小写字母10 个数字标点符号一些控制字符全部加起来不到 128 个。因此决定使用7 位二进制表示所有字符。2^7 128于是 ASCII 的编码范围就是0 ~ 127四、ASCII 里的控制字符很多人第一次看到 ASCII 表都会疑惑为什么前面几十个字符根本不能打印例如编码名称含义0NUL空字符7BEL响铃8BS退格9TAB制表符10LF换行13CR回车27ESC转义这些字符其实不是给人看的。而是给当年的机械设备使用的。例如当时最流行的是电传打字机Teletype。LFLine Feed表示把纸向上移动一行。CRCarriage Return表示把打印头移动到最左边。直到今天Windows 使用CR LFLinux 使用LF都是那个时代留下来的历史遗产。五、ASCII 的优点与局限ASCII 的成功几乎改变了整个计算机行业。它第一次实现了不同计算机之间可以交换文本编程语言可以统一表示字符串操作系统可以统一处理字符但是它有一个致命缺点它只考虑了英语。例如你没有。é没有。ß没有。あ没有。对于美国来说没有问题。但是对于欧洲、中国、日本来说ASCII 根本无法使用。于是新的问题出现了。六、扩展 ASCII第一次尝试解决多语言问题后来计算机普遍采用 8 位字节Byte。工程师发现ASCII 实际只用了 7 位。最高位一直没有使用。于是他们决定把范围扩展到0~255即2^8 256这就是 Extended ASCII。这样欧洲国家终于可以加入é ü ñ ø等字符。看起来问题解决了。实际上更大的问题才刚刚开始。七、代码页Code Page乱码时代的开始欧洲每个国家都希望把自己的字符放进去。于是法国设计了一套。德国设计了一套。俄罗斯设计了一套。日本设计了一套。中国设计了一套。结果同样一个数字130在法国表示é在德国表示ä在俄罗斯表示Ж同一个文件在不同国家打开显示完全不同。这就是无数程序员都遇到过的乱码。微软后来提出了 Code Page代码页的概念。例如CP437CP850CP932CP936GBKCP950不同国家选择不同代码页。虽然本地问题解决了。但是国际交流依然混乱。八、中国自己的字符集GB2312、GBK、GB18030汉字数量远远超过欧洲文字。ASCII 根本无法表示。1980 年中国制定了 GB2312。设计思路非常简单ASCII 保持不变。英文仍然使用一个字节。汉字使用两个字节。例如A ↓ 41但是你 ↓ C4 E3后来随着汉字越来越多。GB2312 已经不够。于是GBK支持两万多个汉字。后来又发展为GB18030。直到今天它仍然是中国的重要国家标准。九、真正的问题世界没有统一字符集到了 1990 年代。整个世界几乎处于美国ASCII欧洲ISO-8859日本Shift-JIS中国GBK韩国EUC-KR俄罗斯KOI8互联网开始普及。电子邮件开始流行。网页开始出现。结果一封邮件发出去。美国正常。中国乱码。日本乱码。俄罗斯乱码。全球软件产业终于意识到不能再让每个国家维护自己的字符集了。十、Unicode给世界上每一个字符发身份证1991 年Unicode 联盟成立。它提出了一个革命性的思想世界上的每一个字符都分配一个唯一编号。例如A ↓ U0041中 ↓ U4E2D ↓ U1F60A注意Unicode 并不是编码方式。它更像一本巨大的字典。里面记录着字符 ↓ 唯一编号世界上所有软件只要遵守 Unicode就不会再因为字符编号不同而发生冲突。十一、Unicode 为什么还需要 UTF-8很多初学者都会误解Unicode 就是 UTF-8。其实不是。Unicode 只规定中 ↓ U4E2D但是如何存进内存如何写进文件如何通过网络发送Unicode 并没有规定。于是出现了不同的编码方式。例如UTF-16UTF-32UTF-8它们都能表示 Unicode。区别只是如何编码。十二、UTF-16Windows 的选择UTF-16 使用两个字节作为基本单位。亚洲文字效率较高。Windows 至今很多内部 API 仍然采用 UTF-16。但是它也存在问题英文原本AASCII1 ByteUTF-162 Bytes对于英文来说浪费空间。另外UTF-16 还存在字节序Endian问题。跨平台处理相对复杂。十三、UTF-8互联网最终的赢家1992 年Ken Thompson 和 Rob Pike 设计出了 UTF-8。UTF-8 有几个极其优秀的特点第一完全兼容 ASCII。例如ASCII A ↓ 41UTF-8A ↓ 41完全一致。第二支持世界所有语言。第三英文仍然只占一个字节。第四网络传输效率高。第五不存在字节序问题。例如A ↓ 41中 ↓ E4 BD A0 ↓ F0 9F 98 8A由于互联网中英文内容占比一直很高。UTF-8 几乎兼顾了兼容性效率扩展性最终成为互联网事实上的统一标准。今天HTMLJSONXMLLinuxGitPythonGoRustJavaScript几乎全部默认采用 UTF-8。十四、字符集发展的本质回顾整个发展过程会发现每一次升级其实都是在解决上一代无法解决的问题。ASCII解决了英文字符统一编码的问题。扩展 ASCII尝试加入更多欧洲字符。Code Page解决各地区本地化问题。GB2312、GBK解决中文输入输出问题。Unicode解决全球字符编号统一问题。UTF-8解决 Unicode 如何高效存储和网络传输的问题。整个字符编码的发展史本质上就是计算机逐渐从只服务英语世界成长为支持全世界所有文字的过程。总结很多初学者会觉得字符集非常复杂。实际上只需要记住一句话字符集Character Set决定一个字符对应什么编号编码Encoding决定这个编号如何存储成字节。ASCII 是字符集也是编码。Unicode 是字符集不是具体编码。UTF-8、UTF-16、UTF-32 是 Unicode 的不同编码方式。理解了这一点再去学习操作系统、网络协议、编译器、数据库、浏览器就会发现很多曾经令人困惑的问题其实都可以归结为一句话计算机从来不认识文字它只认识数字而字符编码就是人类与计算机之间约定好的翻译规则。