1384 字
7 分钟
[programming] 深入理解字符编码:从 ASCII 到 UTF-8 的演进历程

引言#

在日常编程中,我们经常会遇到“乱码”问题。这背后的根源在于字符编码的不统一。字符编码是计算机处理文本信息的基石,从最早的 ASCII 到如今互联网通用的 UTF-8,每一种编码方案的诞生都伴随着技术的演进与时代的特定需求。本文将深入探讨字符编码的历史起源、技术原理及其演变过程。

字符编码的历史起源#

计算机由美国人发明,最初的设计目标是处理数字和英文文本。要让计算机处理文字,首先需要将抽象的字符转换为计算机能够识别的数字。美国人面临的首要问题是:如何将他们国家使用的字符存储在计算机中?

这些字符主要分为三类:

  1. 可见字符:英文字母(大写与小写)、数字、标点符号。
  2. 控制字符:用于控制打印机等设备的肉眼不可见字符,如回车(CR)、换行(LF)等。

ASCII:计算机的“母语”#

控制字符与可见字符#

美国人将这些字符按顺序罗列,分配了从 0 到 127 的编号。这些编号被称为码位(Code Point)

  • 码位 0 ~ 31 以及 127:共 33 个控制字符。
  • 码位 32 ~ 126:共 95 个可见字符。

这个包含 128 个字符的集合被称为 ASCII 字符集

码位与二进制存储#

为了将这些字符存储 in 计算机中,美国人直接将码位转换为二进制信息。由于 128 个字符只需要 7 位二进制(27=1282^7 = 128),计算机通常使用 1 个字节(8 位)来存储,并将最高位设为 0。这种存储方式产生的二进制信息即为 ASCII 码

扩展 ASCII 与多国语言的挑战#

随着计算机进入欧洲,法国、德国等国家发现自己的特殊字母(如带有变音符号的字母)不在 ASCII 字符集中。于是,他们在 ASCII 的基础上进行了扩展:将最高位从 0 变为 1,从而扩展到了 255(28=2562^8 = 256),新增了 128 个字符。这被称为 扩展 ASCII 字符集

NOTE

扩展 ASCII 解决了部分欧洲语言的问题,但对于拥有数以千计字符的亚洲语言(如中文、日语)来说,256 个码位仍然远远不够。

中文编码的演进:GB2312、GBK 与 GB18030#

GB2312 的分区管理#

为了处理汉字,中国制定了 GB2312 标准。GB2312 使用两个字节(16 位)来表示一个字符,采用了“分区管理”的方式:

  • 设计了 94 个区,每个区包含 94 个位,共 8836 个码位。
  • 1~9 区:收录符号、数字等非汉字字符。
  • 16~55 区:收录 3755 个一级汉字(按拼音排序)。
  • 56~87 区:收录 3008 个二级汉字(按部首笔画排序)。

兼容性与 A0 偏移量#

为了向下兼容 ASCII,计算机必须能够区分一个字节代表的是 ASCII 还是 GB2312 的一部分。 GB2312 的存储方式如下:

  1. 将区号和位号分别加上 A0(十六进制)。
  2. 例如,“丙”字在 17 区 93 位,变换后高位和低位均大于 127。
TIP

计算机通过判定字节大小来区分:如果字节小于 127,则按 ASCII 处理;如果连续碰到两个大于 127 的字节,则将其组合为一个 GB2312 汉字。

从 GBK 到 GB18030#

随着需求增加,后续又推出了 GBK 字符集(扩展了近 2 万个汉字)和 GB18030(新增了少数民族字符),它们都保持了对 GB2312 的基本兼容逻辑。

Unicode:打破“乱码”的万国码标准#

当每个国家都设计自己的编码时,信息交流就会产生“乱码”。为了规范化,ISO 组织提出了 Unicode 标准,旨在将全球所有语言的字符都放入一个集合中。

UCS-2 与 UCS-4#

  • UCS-2:使用 16 位,可表示 65536 个字符。
  • UCS-4:使用 32 位,理论上可表示约 43 亿个字符,足以涵盖所有已知语言。

存储空间的挑战#

虽然 Unicode 解决了统一性问题,但直接存储(如 UCS-4)会导致空间浪费。原本只需 1 个字节的 ASCII 字符现在需要 4 个字节,存储效率极低。

UTF-8:互联网时代的通用方案#

UTF-8 是一种针对 Unicode 的可变长编码格式。它根据字符的码位范围,将其编码为 1 到 4 个字节。

可变长编码机制#

码位范围 (十六进制)字节数字节 1 位模式字节 2 位模式字节 3 位模式字节 4 位模式
0000 - 007F10xxxxxxx
0080 - 07FF2110xxxxx10xxxxxx
0800 - FFFF31110xxxx10xxxxxx10xxxxxx
010000 - 10FFFF411110xxx10xxxxxx10xxxxxx10xxxxxx

UTF-8 的编码计算实例#

以汉字“王”为例:

  1. 在 Unicode 中的码位是 U+738B
  2. 属于第三区间(0800 - FFFF),需 3 字节。
  3. 位模式为:1110xxxx 10xxxxxx 10xxxxxx
  4. 738B 的二进制 0111 0011 1000 1011 填充进模式:
    • 结果为:11100111 10001110 10001011
    • 转换回十六进制即为:E7 8E 8B

总结#

字符编码的发展史是一部计算机全球化的历史。ASCII 奠定了基础,GB2312/GBK 解决了中文的燃眉之急,而 Unicode 与 UTF-8 则通过统一标准和灵活的存储方式,真正实现了全球信息的无障碍流动。在开发过程中,推荐优先使用 UTF-8 编码,以确保最大的兼容性与标准性。

[programming] 深入理解字符编码:从 ASCII 到 UTF-8 的演进历程
https://www.eustia-astraea.top/posts/programming/character-encoding-explained/
作者
mcsl
发布于
2025-03-08
许可协议
CC BY-NC-SA 4.0