Python 自带了超过 100 种编解码器(codec, encoder/decoder),用于在文本和字节之间相互转换。每个编解码器都有一个名称,如 'utf_8',而且经常有几个别名,如 'utf8'、'utf-8' 和 'U8'。这些名称可以传给 open()、str.encode()、bytes.decode() 等函数的 encoding 参数。示例 4-5 使用 3 个编解码器把相同的文本编码成不同的字节序列。
示例 4-5 使用 3 个编解码器编码字符串“El Niño”,得到的字节序列差异很大
>>> for codec in ['latin_1', 'utf_8', 'utf_16']: ... print(codec, 'El Niño'.encode(codec), sep='\t') ... latin_1 b'El Ni\xf1o' utf_8 b'El Ni\xc3\xb1o' utf_16 b'\xff\xfeE\x00l\x00 \x00N\x00i\x00\xf1\x00o\x00'
图 4-1 展示了不同编解码器对“A”和高音谱号等字符编码后得到的字节序列。注意,后 3 种是可变长度的多字节编码。

图 4-1:12 个字符,它们的码位及不同编码的字节表述(十六进制,星号表明该编码不支持表示该字符)
图 4-1 中的星号表明,某些编码(如 ASCII 和多字节的 GB2312)不能表示所有 Unicode 字符。然而,UTF 编码的设计目的就是处理每一个 Unicode 码位。
图 4-1 中展示的是一些典型编码,介绍如下。
latin1(即 iso8859_1)
一种重要的编码,是其他编码的基础,例如 cp1252 和 Unicode(注意,latin1 与 cp1252 的字节值是一样的,甚至连码位也相同)。
cp1252
Microsoft 制定的 latin1 超集,添加了有用的符号,例如弯引号和€(欧元);有些 Windows 应用把它称为“ANSI”,但它并不是 ANSI 标准。
cp437
IBM PC 最初的字符集,包含框图符号。与后来出现的 latin1 不兼容。
gb2312
用于编码简体中文的陈旧标准;这是亚洲语言中使用较广泛的多字节编码之一。
utf-8
目前 Web 中最常见的 8 位编码;3 与 ASCII 兼容(纯 ASCII 文本是有效的 UTF-8 文本)。
3W3Techs 发布的“Usage of character encodings for websites”(https://w3techs.com/technologies/overview/character_encoding/all)报告指出,截至 2014 年 9 月,81.4% 的网站使用 UTF-8;而 Built With 发布的“Encoding Usage Statistics”(http://trends.builtwith.com/encoding)估计的比例则是 79.4%。
utf-16le
UTF-16 的 16 位编码方案的一种形式;所有 UTF-16 支持通过转义序列(称为“代理对”,surrogate pair)表示超过 U+FFFF 的码位。
UTF-16 取代了 1996 年发布的 Unicode 1.0 编码(UCS-2)。这个编码在很多系统中仍在使用,但是支持的最大码位是 U+FFFF。从 Unicode 6.3 起,分配的码位中有超过 50% 在 U+10000 以上,包括逐渐流行的表情符号(emoji pictograph)。
概述常规的编码之后,下面要处理编码和解码过程中存在的问题。