首页 > Python基础教程 >
-
Python3标准库:codecs字符串编码和解码(6)
每次将数据传递到编码器或解码器时,其内部状态都会更新。状态一致时(按照codec的定义),会返回数据并重置状态。在此之前,encode()或decode()调用并不返回任何数据。传入最后一位数据时,参数final应当设置为True,这样codec就能知道需要刷新输出所有余下的缓冲数据。
1.8 定义定制编码
由于Python已经提供了大量标准codecs,所以应用一般不太可能需要定义定制的编码器或解码器。不过,如果确实有必要,codecs中的很多基类可以帮助你更容易的定义定制编码。
第一步是了解编码描述的转换性质。这一节中的例子将使用一个“invertcaps”编码,它把大写字母转换为小写,把小写字母转换为大写。下面是一个编码函数的简单定义,它会对输入字符串完成这个转换。
- import string
- def invertcaps(text):
- """Return new string with the case of all letters switched.
- """
- return ''.join(
- c.upper() if c in string.ascii_lowercase
- else c.lower() if c in string.ascii_uppercase
- else c
- for c in text
- )
- if __name__ == '__main__':
- print(invertcaps('ABCdef'))
- print(invertcaps('abcDEF'))
在这里,编码器和解码器都是同一个函数(与ROT-13类似)。
尽管很容易理解,但这个实现效率不高,特别是对于非常大的文本串。幸运的是,codecs包含一些辅助函数,可以创建基于字符映射(character map)的codecs,如invertcaps。字符映射编码由两个字典构成。编码映射(encoding map)将输入串的字符值转换为输出中的字节值,解码映射(decoding map)则相反。首先创建解码映射,然后使用make_encoding_map()把它转换为一个编码映射。C函数charmap_encode()和charmap_decode()可以使用这些映射高效的转换输入数据。
- import codecs
- import string
- # Map every character to itself
- decoding_map = codecs.make_identity_dict(range(256))
- # Make a list of pairs of ordinal values for the lower
- # and uppercase letters
- pairs = list(zip(
- [ord(c) for c in string.ascii_lowercase],
- [ord(c) for c in string.ascii_uppercase],
- ))
- # Modify the mapping to convert upper to lower and
- # lower to upper.
- decoding_map.update({
- upper: lower
- for (lower, upper)
- in pairs
- })
- decoding_map.update({
- lower: upper
- for (lower, upper)
- in pairs
- })
- # Create a separate encoding map.
- encoding_map = codecs.make_encoding_map(decoding_map)
- if __name__ == '__main__':
- print(codecs.charmap_encode('abcDEF', 'strict',
- encoding_map))
- print(codecs.charmap_decode(b'abcDEF', 'strict',
- decoding_map))
- print(encoding_map == decoding_map)
尽管invertcaps的编码和解码映射是一样的,但并不总是如此。有时会把对各输入字符编码为相同的输出字节,make_encoding_map()会检测这些情况,并把编码值替换为None,以标志编码为未定义。
字符映射编码器和解码器支持前面介绍的所有标准错误处理方法,所以不需要做任何额外的工作来支持这部分API。
- import codecs
- import string
- # Map every character to itself
- decoding_map = codecs.make_identity_dict(range