首页 > Python基础教程 >
-
Python3标准库:codecs字符串编码和解码
1. codecs字符串编码和解码
codecs模块提供了流接口和文件接口来完成文本数据不同表示之间的转换。通常用于处理Unicode文本,不过也提供了其他编码来满足其他用途。
1.1 Unicode入门
CPython 3.x区分了文本(text)和字节(byte)串。bytes实例使用一个8位字节值序列。与之不同,str串在内部作为一个Unicode码点(code point)序列来管理。码点值使用2字节或4字节表示,这取决于编译Python时指定的选项。
输出str值时,会使用某种标准机制编码,以后可以将这个字节序列重构为同样的文本串。编码值的字节不一定与码点值完全相同,编码只是定义了两个值集之间转换的一种方式。读取Unicode数据时还需要知道编码,这样才能把接收到的字节转换为unicode类使用的内部表示。
西方语言最常用的编码是UTF-8和UTF-16,这两种编码分别使用单字节和两字节值序列表示各个码点。对于其他语言,由于大多数字符都由超过两字节的码点表示,所以使用其他编码来存储可能更为高效。
要了解编码,最好的方法就是采用不同方法对相同的串进行编码,并查看所生成的不同的字节序列。下面的例子使用以下函数格式化字节串,使之更易读。
- import binascii
- def to_hex(t, nbytes):
- """Format text t as a sequence of nbyte long values
- separated by spaces.
- """
- chars_per_item = nbytes * 2
- hex_version = binascii.hexlify(t)
- return b' '.join(
- hex_version[start:start + chars_per_item]
- for start in range(0, len(hex_version), chars_per_item)
- )
- if __name__ == '__main__':
- print(to_hex(b'abcdef', 1))
- print(to_hex(b'abcdef', 2))
这个函数使用binascii得到输入字节串的十六进制表示,在返回这个值之前每隔nbytes字节就插入一个空格。
第一个编码示例首先使用unicode类的原始表示来打印文本'francais',后面是Unicode数据库中各个字符的名。接下来两行将这个字符串分别编码为UTF-8和UTF-16,并显示编码得到的十六进制值。
- import unicodedata
- import binascii
- def to_hex(t, nbytes):
- """Format text t as a sequence of nbyte long values
- separated by spaces.
- """
- chars_per_item = nbytes * 2
- hex_version = binascii.hexlify(t)
- return b' '.join(
- hex_version[start:start + chars_per_item]
- for start in range(0, len(hex_version), chars_per_item)
- )
- text = 'français'
- print('Raw : {!r}'.format(text))
- for c in text:
- print(' {!r}: {}'.format(c, unicodedata.name(c, c)))
- print('UTF-8 : {!r}'.format(to_hex(text.encode('utf-8'), 1)))
- print('UTF-16: {!r}'.format(to_hex(text.encode('utf-16'), 2)))
对一个str编码的结果是一个bytes对象。
给定一个编码字节序列(作为一个bytes实例),decode()方法将其转换为码点,并作为一个str实例返回这个序列。
- import binascii
- def to_hex(t, nbytes):
- """Format text t as a sequence of nbyte long values
- separated by spaces.
- """
- chars_per_item = nbytes * 2
- hex_version = binascii.hexlify(t)
- return b' '.join(
- hex_version[start:start + chars_per_item]
- for start in range(0, len(hex_version), chars_per_item)
- )
- text = 'français'
- encoded = text.encode('utf-8')
- decoded = encoded.decode('utf-8')
- print('Original :', repr(text))
- print('Encoded :', to_hex(encoded, 1), type(encoded))
- print('Decoded :', repr(decoded), type(decoded))
选择使用哪一种编码不会改变输出类型。
1.2 处理文件
处理I/O操作时,编码和解码字符串尤其重要。不论是写至一个文件、套接字还是其他流,数据都必须使用适当的编码。一般来讲,所有文本数据在读取时都需要由其字节表示解码,写数据时则需要从内部值编码为一种特定的表示。程序可以显式的编码和解码数据,不过取决于所用的编码,要想确定是否已经读取足够的字节来充分解码数据,这可能并不容易。codecs提供了一些类来管理数据编码和解码,所以应用不再需要做这个工作。
codecs提供的最简单的接口可以替代内置open()函数。这个新版本的函数与内置函数的做法很相似,不过增加了两个参数来指定编码和所需的错误处理技术。
- import binascii
- import codecs
- def to_hex(t, nbytes):
- """Format text t as a sequence of nbyte long values
- separated by spaces.
- """
- chars_per_item = nbytes * 2
- hex_version = binascii.hexlify(t)
- return b' '.join(
- hex_version[start:start + chars_per_item]
- for start in range