Unicode 编码

为了介绍 Python 的编码知识,我们先来回顾下计算机发展历史上文字是如何编码的。

计算机在美国被发明之后,一开始需要被存储的字符个数不多,包括大小写的英语字母以及常用的标点符号,在 7 个 bit 内就能把所有的适用于美国当时要求的字符给枚举出来,这就是 ASCII 码,是 American Standard Code for Information Interchange 的首字母缩写。

计算机继续推广后,在文字记录上首先遇到的问题就是即使是跟英语相近的语言,比如法语等,它们有很多的字母需要在正常的字母上方加上比如冒号等符号,例如éÍ ,那 7 个 bit 就不够用了。于是各个语言就开始在 ASCII 的基础上扩充,扩充到了一个字节,也就是 8 个 bit。法语加上法语自己的一些特殊字母成了一个新的编码集,俄语加上自己的西里尔字母也成了一个新的编码集。这些尝试在自己语言内部是没有问题,但是一个文档中需要混合两种以上的语言时候,就出现错误了,没有一个编码集能够覆盖全部语言。

这就是后来为什么又把编码扩充到了两个字节,或者 16 个 bit 的原因,用一个超大的编码集把所有的文字都包含进来,这种努力直到字符集的长度变为了 21 个 bit,也就是字符编码的范围从 00x10FFFF,才真正的把世界上所有的文字都囊括进去了。最后的这个编码标准,就是 ISO 10646,或者也可以说是 Unicode

回顾完了历史,我们来看什么是 UTF-8。现有的 ISO10646 解决了编码的终极问题,任何字符都可以在这个编码集中找到自己的位置,但是如果我们用这种方法来存储文字的话,就会有一个问题了,太浪费空间。因为常用的字符都可以在 8 个比特或者 16 个比特内找到自己的位置,假如我们都有 21 个比特来存储字符的话,效率大概只有 30%-50%,所有就出现了类似 UTF-8 这样的编码,它也是现行被采用最多的编码方式。

UTF-8UTF 的意思是 Unicode Transformation Format-Unicode 转换格式,8 的意思是 8 比特编码。它的规则如下,

  1. 假如编码数字<128,就采用用相应的编码值。
  2. 假如编码数字>128,就分别用 2、3 或 4 个字节来表示,其中每个字节的取值范围在 128-255,也即是最高位都为 1,是为了跟 ASCII 区分开,ASCII 的字节最高位 bit 是 0

Python 3 以后,字符串存储都是以 unicode 的方式来存储了,而不像 Python 2 中那样字符串是默认以 bytes 来存储的。

# Python 3
type("f") == type(u"f")  # True, <class 'str'>
type(b"f")               # <class 'bytes'>

# Python 2
type("f") == type(b"f")  # True, <type 'str'>
type(u"f")               # <type 'unicode'>