常见错误

UnicodeEncodeError
UnicodeDecodeError

字节与字符

计算机存储的一切数据,文本字符、图片、视频、音频、软件都是由一串01的字节序列构成的,一个字节等于8个比特位。

而字符就是一个符号,比如一个汉字、一个英文字母、一个数字、一个标点都可以称为一个字符。

字节方便存储和网络传输,而字符用于显示,方便阅读。字符 “p” 保存到硬盘就是一串二进制数据 01110000,占用一个字节的长度。

编码与解码

我们用编辑器打开的文本,看到的一个个字符,最终保存在磁盘的时候都是以二进制字节序列形式存起来的。

那么从字符到字节的转换过程就叫做编码(encode),反过来叫做解码(decode)

两者是一个可逆的过程。编码是为了存储传输,解码是为了方便显示阅读。
例如字符 “p” 保存到硬盘是一串二进制 01110000 ,占用一个字节的长度。
Python 使用 ASCII 字符编码作为默认编码方式,而 ASCII 不能处理中文。

Python2 把字符串分为 unicode 和 str 两种类型。
unicode 和 str
str 本质上其实是一串二进制数据,而 unicode 是字符(符号),编码(encode)就是把字符(符号)转换为 二进制数据的过程,因此 unicode 到 str 的转换要用 encode 方法,反过来就是用 decode 方法。

UnicodeEncodeError

UnicodeEncodeError 发生在 unicode 字符串转换成 str 字节序列的时候。

调用 write 方法时,Python 会先判断字符串是什么类型,如果是 str,就直接写入文件,不需要编码,因为 str 类型的字符串本身就是一串二进制的字节序列了。

如果字符串是 unicode 类型,那么它会先调用 encode 方法把 unicode 字符串转换成二进制形式的 str 类型,才保存到文件,而 encode 方法会使用 python 默认的 ascii 码来编码。

ASCII 字符集中只包含了128个拉丁字母,不包括中文字符,因此 出现了 ‘ascii’ codec can’t encode characters 的错误。要正确地使用 encode ,就必须指定一个包含了中文字符的字符集,比如:UTF-8、GBK。

UnicodeDecodeError

1.UnicodeDecodeError 发生在 str 类型的字节序列解码成 unicode 类型的字符串时

1
2
3
4
b = a.encode("utf-8")
b.decode("gbk")

UnicodeDecodeError: 'gbk' codec can't decode byte 0x85 in position 2

把一个经过 UTF-8 编码后生成的字节序列 ‘\xe7\xa6\x85’ 再用 GBK 解码转换成 unicode 字符串时,出现 UnicodeDecodeError,因为 (对于中文字符)GBK 编码只占用两个字节,而 UTF-8 占用3个字节,用 GBK 转换时,还多出一个字节,因此它没法解析。避免 UnicodeDecodeError 的关键是保持 编码和解码时用的编码类型一致。

2.str 与 unicode 字符串 执行 + 操作

1
2
3
4
5
x + y

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

str 与 unicode 字符串 执行 + 操作时,Python 会把 str 类型的字节序列隐式地转换成(解码)成 和 x 一样的 unicode 类型,但Python是使用默认的 ascii 编码来转换的,而 ASCII 中不包含中文,所以会报错。

正确地方式应该是显示地把 y 用 UTF-8 或者 GBK 进行解码。

1
2
y = y.decode("utf-8")
x + y