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(注意,latin1cp1252 的字节值是一样的,甚至连码位也相同)。

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)。

概述常规的编码之后,下面要处理编码和解码过程中存在的问题。