编码和解码
下面一张图搞懂编码、解码、编码表之间的关系。
![](https://img.haomeiwen.com/i16044147/7b438c6d27f5d25a.png)
不难看出,它们是一种根据编码表进行翻译、映射的过程:
- 编码:str --> bytes
- 解码:bytes --> str
实际上,字符串类型只有encode()方法,没有decode()方法,而bytes类型只有decode()方法而没有encode()方法。
>>> set( dir(str) ) - set( dir(bytes) )
{'encode', ... , 'isidentifier', 'format'}
>>> set( dir(bytes) ) - set( dir(str) )
{'decode', 'hex', 'fromhex'}
二进制格式的数据也常称为裸数据(raw data),所以str数据经过编码后得到raw data,raw data解码后得到的str。
python中的编码、解码
上面说了,编码是将字符数据转换成字节数据(raw data),解码是将字节数据转换成字符数据。在Python中字符数据也就是字符串,即str类型,字节数据也就是bytes类型或bytearray类型。
编码时,可以使用字节类型的构造方法bytes()、bytearray()来构造字节,也可以使用str类型的encode()方法来转换。
解码时,可以使用str类型的构造方法str()来构造字符串,也可以使用bytes、bytearray()类型的decode()方法。
另外需要注意的是,编码和解码的过程中都需要指定编码表(字符集),默认采用的是utf-8字符集。
编码过程
例如,使用encode()的方式将str编码为bytes数据。
>>> str1 = "abcd"
>>> str2 = "我爱你"
# 默认编码
>>> str1.encode()
b'abcd'
>>> str2.encode()
b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0'
# 显式指定使用utf-8进行编码
>>> str1.encode("utf-8")
b'abcd'
>>> str2.encode("utf-8")
b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0'
# 使用utf-16编码
>>> str1.encode("utf-16")
b'\xff\xfea\x00b\x00c\x00d\x00'
>>> str2.encode("utf-16")
b'\xff\xfe\x11b1r`O'
# 使用gb2312编码
>>> str1.encode("gb2312")
b'abcd'
>>> str2.encode("gb2312")
b'\xce\xd2\xb0\xae\xc4\xe3'
# 使用gbk编码
>>> str1.encode("gbk")
b'abcd'
>>> str2.encode("gbk")
b'\xce\xd2\xb0\xae\xc4\xe3'
使用bytes()和bytearray()将str构造成bytes或bytearray数据,这两个方法都要求str->byte的过程中给定编码。
>>> bytes(str1,encoding="utf-8")
b'abcd'
>>> bytes(str1,encoding="utf-16")
b'\xff\xfea\x00b\x00c\x00d\x00'
>>> bytearray(str1,encoding="utf-8")
bytearray(b'abcd')
>>> bytearray(str2,encoding="utf-8")
bytearray(b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0')
实际上,bytes()、bytearray()这两个方法构造字节数据的时候还有点复杂,因为可以从多个数据源来构造,比如字符串、整数值、buffer。如何使用这两个方法构造字节数据,详细内容参考help(bytes)和help(bytearray)给出的说明,这里给几个简单示例。
构造bytes的方式:
# 构造空bytes对象
>>> bytes()
b''
# 使用str构造bytes序列,需要指定编码
>>> bytes("abcd",encoding="utf-8")
b'abcd'
# 使用int初始化5个字节的bytes序列
>>> bytes(5)
b'\x00\x00\x00\x00\x00'
# 使用可迭代的int序列构造字节序列
# int值必须为0-256以内的数
>>> bytes([65,66,67])
b'ABC'
# 使用bytes或buffer来构造bytes对象
>>> bytes(b'abcd')
b'abcd'
构造bytearray的方式:
# 构造空bytearray对象
>>> bytearray()
bytearray(b'')
# 使用bytes或buffer构造bytearray序列
>>> bytearray(b"abcd")
bytearray(b'abcd')
# 使用str构造bytearray序列,需要指定编码
>>> bytearray("abcd",encoding="utf-8")
bytearray(b'abcd')
# 使用int初始化5个字节的bytearray序列
>>> bytearray(5)
bytearray(b'\x00\x00\x00\x00\x00')
# 使用可迭代的int序列构造bytearray序列
# int值必须为0-256以内的数
>>> bytearray([65,66,67])
bytearray(b'ABC')
解码过程
解码是字节序列到str类型的转换。
例如,使用decode()方法进行解码"我"字,它的utf-8的编码对应为"\xe6\x88\x91":
>> b = b'\xe6\x88\x91'
# 采用默认字符集utf-8
>>> b.decode()
'我'
# 显式指定编码表
>>> b.decode("utf-8")
'我'
使用str()进行转换。
>>> str(b,"utf-8")
'我'
关于乱码
当编码、解码的过程使用了不同的(不兼容的)编码表时,就会出现乱码。所以,解决乱码的唯一方式是指定对应的编码表进行编码、解码。
例如,使用utf-8编码"我"字,得到一个bytes序列,然后使用gbk解码这个bytes序列。
>>> "我".encode().decode("gbk")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'gbk' codec can't decode byte 0x91 in position 2: incomplete multibyte sequence
这里报错了,因为utf-8的字节序列里有gbk无法解码的字节。如果使用文本编辑器一样的工具去显化这个过程,得到的将是乱码字符。
网友评论