字符编码器
常见的编码器
Python 自带了超过 100 种编解码器(codec,encoder/decoder),用于在文本和字节之间相互转换。 例如:‘utf_8’,‘utf_16’…
需要设置编码器参数的主要用于如下函数:
- open()
- str.encode()
- bytes.decode()
如下实例:
# 不同的编码的格式
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'
主要的编码格式如下
- latin1(即 iso8859_1):一 种 重 要 的 编 码, 是 其 他 编 码 的 基 础,
- cp1252: Microsoft 制定的 latin1 超集,添加了有用的符号
- cp437:IBM PC 最初的字符集,包含框图符号。
- gb2312:用于编码简体中文的陈旧标准
- utf-8:目前 Web 中最常见的 8 位编码
- utf-16le:UTF-16 的 16 位编码方案的一种形式;所有 UTF-16 支持通过转义序列
编解码问题处理
- 处理UnicodeEncodeError
- 目标编码中没有定义某个字符
- 处理UnicodeDecodeError
- 遇到无法转换的字节序列
处理UnicodeEncodeError
多数非 UTF 编解码器只能处理 Unicode 字符的一小部分子集。把文本转换成字节序列时,如果目标编码中没有定义某个字符,那就会抛出UnicodeEncodeError 异常,
city ='São Paulo'
print(city.encode('utf_8'))
print(city.encode('utf_16'))
print(city.encode('iso8859_1'))
# cp437无法处理ã,会报错误UnicodeEncodeError
# 'charmap' codec can't encode character'\xe3'
# print(city.encode('cp437'))
# 处理如下:跳过无法编码的字符
print(city.encode('cp437',errors='ignore'))
# 处理如下:把无法编码的字符替换成 '?'
print(city.encode('cp437',errors='replace'))
# 处理如下:无法编码的字符替换成 XML 实体
print(city.encode('cp437',errors='xmlcharrefreplace'))
b'S\xc3\xa3o Paulo'
b'\xff\xfeS\x00\xe3\x00o\x00 \x00P\x00a\x00u\x00l\x00o\x00'
b'S\xe3o Paulo'
b'So Paulo'
b'S?o Paulo'
b'São Paulo'
处理UnicodeDecodeError
不是每一个字节都包含有效的 ASCII 字符,也不是每一个字符序列都是有效的 UTF-8 或UTF-16。因此,把二进制序列转换成文本时,如果假设是这两个编码中的一个,遇到无法转换的字节序列时会抛出 UnicodeDecodeError。
octets = b'Montr\xe9al'
print(octets.decode('cp1252'))
print(octets.decode('iso8859_7'))
print(octets.decode('koi8_r'))
# 'utf-8' codec can't decode byte 0xe9
# 无法解码:抛出 UnicodeDecodeError
#print(octets.decode('utf_8'))
# \xe9 替换成了“�”
print(octets.decode('utf_8',errors='replace'))
Montréal
Montrιal
MontrИal
Montr�al
编码加载模块时抛出的SyntaxError
Python 3 默认使用 UTF-8 编码源码,Python 2(从 2.5 开始)则默认使用 ASCII.如果加载的 .py 模块中包含 UTF-8 之外的数据,而且没有声明编码.加载模块时抛出的SyntaxError.
#编码加载模块时抛出的SyntaxError的处理
# coding: cp1252
print('Olá, Mundo!')
print("瓦力人工智能")
Olá, Mundo!
瓦力人工智能
字节序列的编码的查找
如果所给的字节序列没有明确说明,是不能找到该字节序列是采用何种编码格式。但是我们可以根据里面的一下细节来试探和分析找出器编码格式。
可以采用统一字符编码侦测包 Chardet
识别所支持的 30 种编码。Chardet 是一个 Python 库,可以在程序中使用,不过它也提供了命令行工具 chardetect。
BOM:有用的字序节标记
UTF-16 编码的序列开头有几个额外的字节b'\xff\xfe\xe6t\x9bR\xbaN\xe5]zf\xfd\x80'
里面出现的b'\xff\xfe
就是 BOM(byte-order mark)字节序标记.这里表明:我编码的时候使用的是Intel CPU的小字节序.
Windows 应用(尤其是 Notepad)依然会在 UTF-8 编码的文
件中添加 BOM,UTF-8 编码的 U+FEFF 字符是一个三字节序列:b'\xef\xbb\xbf'
u16 = '瓦力人工智能'.encode('utf_16')
print(u16)
print(list(u16))
b'\xff\xfe\xe6t\x9bR\xbaN\xe5]zf\xfd\x80'
[255, 254, 230, 116, 155, 82, 186, 78, 229, 93, 122, 102, 253, 128]