首页 > Python基础教程 >
-
Python3标准库:codecs字符串编码和解码(4)
第一种选项,要确保应用显式的为所有I/O操作设置正确的编码,strict模式是最安全的选择,但是产生一个异常时,这种模式可能导致程序崩溃。
第二种选项,replace确保不会产生错误,其代价是一些无法转换为所需编码的数据可能会丢失。pi(π)的Unicode字符仍然无法用ASCII编码,但是采用这种错误处理模式时,并不是产生一个异常,而是会在输出中将这个字符替换为?。
第三种选项,无法编码的数据都会被丢弃。
第四种选项,会把字符替换为标准中定义的一个与该编码不同的候选表示。xmlcharrefreplace使用一个XML字符引用作为替代。
第五种选项,和第四种一样会把字符替换为标准中定义的一个与该编码不同的候选表示。它生成的输出格式类似于打印unicode对象的repr()时返回的值。Unicode字符会被替换为\u以及码点的十六进制值。
1.4.2 编码错误
数据编码时也有可能遇到错误,特别是如果使用了错误的编码。
- import codecs
- 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)
- )
- error_handlings = ['strict','ignore','replace']
- text = 'français'
- for error_handling in error_handlings:
- print('Original :', repr(text))
- # Save the data with one encoding
- with codecs.open('decode_error.txt', 'w',
- encoding='utf-16') as f:
- f.write(text)
- # Dump the bytes from the file
- with open('decode_error.txt', 'rb') as f:
- print('File contents:', to_hex(f.read(), 1))
- # Try to read the data with the wrong encoding
- with codecs.open('decode_error.txt', 'r',
- encoding='utf-8',
- errors=error_handling) as f:
- try:
- data = f.read()
- except UnicodeDecodeError as err:
- print('ERROR:', err)
- else:
- print('Read :', repr(data))
与编码一样,如果不能正确的节码字节流,则strict错误处理模式会产生一个异常。在这里,产生UnicodeDecodeError的原因是尝试使用UTF-8解码器将UTF-16BOM部分转换为一个字符。
切换到ignore会让解码器跳过不合法的字节。不过,结果仍然不是原来指望的结果,因为其中包括嵌入的null字节。
采用replace模式时,非法的字节会被替换为\uFFFD,这是官方的Unicode替换字符,看起来像是一个有黑色背景的菱形,其中包含一个白色的问号。
1.5 编码转换
尽管大多数应用都在内部处理str数据,将数据解码或编码作为I/O操作的一部分,但有些情况下,可能需要改变文件的编码而不继续坚持这种中间数据格式,这可能很有用。EncodedFile()取一个使用某种编码打开的文件句柄,用一个类包装这个文件句柄,有I/O操作时它会把数据转换为另一种编码。
- import binascii
- import codecs
- import io
- 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)
- )
- # Raw version of the original data.
- data = 'français'
- # Manually encode it as UTF-8.
- utf8 = data.encode('utf-8')
- print('Start as UTF-8 :', to_hex(utf8, 1))
- # Set up an output buffer, then wrap it as an EncodedFile.
- output = io.BytesIO()
- encoded_file = codecs.EncodedFile(output, data_encoding='utf-8',
- file_encoding='utf-16'