在codecs模块里定义了与codec对象进行交互的接口,也可以使用它作为其它编解码的基类。 在Python里要求codec对象需要有四个接口:无状态的encoder,无状态的decoder,StreamReader和StreamWriter。而StreamReader和StreamWriter通常是由无状态的encoder/decoder通过文件协议来实现。同时codec对象还需要处理在编码和解码里出现的错误。
4.2.1.1 错误处理
codecs模块通过errors字符串参数来实现不同的错误处理,同时为了简化和标准化错误处理,需要定义错误标准处理如下:
值 | 意义 |
‘strict’ | 抛出异常UnicodeError;默认的情况下选用这个方式,具体实现在函数strict_errors()里。 |
‘ignore’ | 忽略错误数据,并且不提示出错。具体实现在函数codecs.ignore_errors()。 |
下面是在文本编解码时的错误处理:
值 | 意义 |
‘replace’ | 不合法的字符使用指定字符替换。在解码出错时使用U+FFFD来替换,在编码时使用‘?’替换。具体实现在函数replace_errors()函数。 |
‘xmlcharrefreplace’ | 当在XML字符编码时,修改为合适的XML引用代替。具体实现在函数xmlcharrefreplace_errors()。 |
‘backslashreplace’ | 当在编码时,不认识字符可以使用反斜杠序列来代替。具体实现函数在backslashreplace_errors()。 |
‘surrogateescape’ | 当在解码和编码时使用替代字符,比如空字符在UTF8里可能是结束标记,但又需要对它进行编码,就需要使用替换字符来解决。具体情况请参考PEP 383。 |
在utf-8, utf-16, utf-32, utf-16-be, utf-16-le, utf-32-be, utf-32-le编码和解码里,可以采用surrogatepass的错误处理方式。
通过下面的函数可以设置新的错误处理方式:
codecs.register_error(name, error_handler)
注册一个以name名称的错误处理函数error_handler。当编码或者解码出错时,就会调用此函数进行处理。name是作为一个错误参数与解码或编码时传入参数进行比较。
例子:
#python 3.4.3
import codecs
codecs.register_error('test', codecs.strict_errors)
fun = codecs.lookup_error('test')
print(fun)
结果输出如下:
<built-in function strict_errors>
codecs.lookup_error(name)
通过名称查找错误处理函数返回,如果没有发现抛出异常LookupError。
例子:
#python 3.4.3
import codecs
codecs.register_error('test', codecs.strict_errors)
fun = codecs.lookup_error('test007')
print(fun)
结果输出如下:
Traceback (most recent call last):
File "E:\codecs1.py", line 5, in <module>
fun = codecs.lookup_error('test007')
LookupError: unknown error handler name 'test007'
codecs.strict_errors(exception)
实现‘strict’方式的错误处理函数,每次编码或解码出错时抛出异常UnicodeError。
codecs.replace_errors(exception)
实现‘replace’方式的错误处理函数。
codecs.ignore_errors(exception)
实现‘ignore’方式的错误处理函数。
codecs.xmlcharrefreplace_errors(exception)
实现‘xmlcharrefreplace’方式的错误处理函数。
codecs.backslashreplace_errors(exception)
实现‘backslashreplace’方式的错误处理函数。
例子:
#python 3.4.3
import codecs
import unittest
def test_badandgoodstrictexceptions(self):
# "strict" complains about a non-exception passed in
self.assertRaises(
TypeError,
codecs.strict_errors,
42
)
# "strict" complains about the wrong exception type
self.assertRaises(
Exception,
codecs.strict_errors,
Exception("ouch")
)
# If the correct exception is passed in, "strict" raises it
self.assertRaises(
UnicodeEncodeError,
codecs.strict_errors,
UnicodeEncodeError("ascii", u"\u3042", 0, 1, "ouch")
)
if __name__ == '__main__':
unittest.main()
结果输出如下:
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
4.2.1.2 无状态的编码和解码处理
在Codec的基类里定义无状态的编码和解码处理,也就是encoder和decoder的相关接口函数。具体如下:
Codec.encode(input[, errors])
对输入对象input进行编码,然后返回元组对象(输出对象,数据长度)。例如,在文本编码里转换一个字符串对象到一个bytes对象。errors是定义错误处理方式,默认是strict处理方式。本基类不提供保存状态在Codec实例对象里,如果需要保存状态需要使用StreamCodec作为基类对象。enocde函数需要考虑0个字符的输入情况,并能返回空对象。
Codec.decode(input[, errors])
对输入对象input进行解码,然后返回元组对象(输出对象,数据长度)。例如,在文本编码里转换一个bytes对象到合适编码的字符串对象。对文本编码或者字节到字节的转换里,参数input要求是一个bytes对象,或者提供缓冲区访问协议的对象。errors是定义错误处理方式,默认是strict处理方式。本基类不提供保存状态在Codec实例对象里,如果需要保存状态需要使用StreamCodec作为基类对象。enocde函数需要考虑0个字符的输入情况,并能返回空对象。
例子:
#python 3.4.3
import codecs
# Stateless encoder/decoder
class TestCodec(codecs.Codec):
def encode(self, input, errors='strict'):
return ('abc', 3)
def decode(self, input, errors='strict'):
return ('abc', 3)
# Incremental forms
class TestCodecIncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input, final=False):
return 'abc'
class TestCodecIncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input, final=False):
return 'abc'
# Stream reader and writer
class TestCodecStreamReader(TestCodec, codecs.StreamReader):
pass
class TestCodecStreamWriter(TestCodec, codecs.StreamWriter):
pass
def find_TestCodec(encoding):
"""Return the codec for 'testcodec'.
"""
if encoding == 'testcodec':
print(encoding)
return codecs.CodecInfo(
name='testcodec',
encode=TestCodec().encode,
decode=TestCodec().decode,
incrementalencoder=TestCodecIncrementalEncoder,
incrementaldecoder=TestCodecIncrementalDecoder,
streamreader=TestCodecStreamReader,
streamwriter=TestCodecStreamWriter,
)
return None
#注册新的编解码对象
codecs.register(find_TestCodec)
encoder = codecs.getencoder('testcodec')
text = 'abc.DEF'
encoded_text, consumed = encoder(text)
print(encoded_text, consumed)
结果输出如下:
testcodec
abc 3
在这个例里的注意点是编码器的名称一定要是全部小写字符命名,否则查找不到。
4.2.1.3 有状态的编码和解码处理
对有状态的编码和解码处理主要提供两个基类的接口,这两个基类分别是:IncrementalEncoder和IncrementalDecoder。前面两个基类encoder和decoder 是无状态的基类接口,只需要调用一次就处理完成,而后面两个基类提供的接口函数是可以多次调用,递增方式进行编码和解码,并且跟踪多次调用之间的状态。
4.2.1.3.1 IncrementalEncoder对象
基类IncrementalEncoder 主要用来对多步输入进行编码,主要定义下面的接口,以便可以符合Python注册Codec编解码器的标准。
class codecs.IncrementalEncoder(errors='strict')
构造一个递增式的编码实现对象。所有基于IncrementalEncoder类的派生类,必须实现此接口,这个接口的参数是可以自由定义的,不过必须有errors这个参数,以便给codec注册时使用。同时IncrementalEncoder也可以依据errors提供不同的错误处理,具体工作请参考前面介绍的错误处理方式。
encode(object[, final])
对输入对象object进行编码,如果最后一次调用需要设置final为True,返回编码后的对象。
reset()
复位编码对象为初始状态。
IncrementalEncoder.getstate()
获取当前编码对象的状态码,用整数表示。实现上要求通用的状态码为0表示。
IncrementalEncoder.setstate(state)
设置编码对象所处的状态。
4.2.1.3.2 IncrementalDecoder对象
基类IncrementalDecoder实现多步骤解码的接口。
class codecs.IncrementalDecoder(errors='strict')
构造一个递增式的解码实现对象。所有基于IncrementalDecoder类的派生类,必须实现此接口,这个接口的参数是可以自由定义的,不过必须有errors这个参数,以便给codec注册时使用。同时IncrementalDecoder也可以依据errors提供不同的错误处理,具体工作请参考前面介绍的错误处理方式。
decode(object[, final])
对输入对象object进行解码,如果最后一次调用需要设置final为True,返回解码后的对象。
reset()
复位解码对象为初始状态。
IncrementalDecoder.getstate()
获取当前解码对象的状态码,用整数表示。实现上要求通用的状态码为0表示。
IncrementalDecoder.setstate(state)
设置解码对象所处的状态。
4.2.1.4 流方式编码和解码处理
类StreamWriter和StreamReader是实现新的流编解码处理的基础,它提供了所有接口。
4.2.1.4.1 StreamWriter对象
类StreamWriter是Codec的子类,为了能在Codec里注册,需要所有继承类StreamWriter的派生类都实现下面的接口。
class codecs.StreamWriter(stream, errors='strict')
类StreamWriter的构造函数,用来构造StreamWriter的实例对象。所有继承的类都应实现此接口,参数的个数自由定义,但stream和errors参数必须定义。参数stream必须是文件类似的对象,用来打开文本或二进制的数据。参数errors可以定义不同的错误处理函数。
write(object)
把对象object的内容进行编码然后写到流里面。
writelines(list)
把列表list里的字符串连接起来写到流里面。注意字节到字节的编码不支持。
reset()
立即输出缓冲区里的内容,并复位所有用到的缓冲区。
4.2.1.4.2 StreamReader对象
类StreamReader是Codec的子类,为了能在Codec里注册,需要所有继承类StreamReader的派生类都实现下面的接口。
class codecs.StreamReader(stream, errors='strict')
构造一个StreamReader对象实例,所有继承此类的类都要实现此接口。至少定义两个参数,其它参数按需要添加。参数stream是文件类似的对象,用来打开读取文件或二进制数据。可以根据参数errors实现在解码处理过程中出错时不同的错误处理。
read([size[, chars[, firstline]]])
从流对象里读取数据并解码,返回数据对象。 参数chars是指明解码需要多少个字节。参数size是最大解码需要的字节数,或者需要读取多少字节来解码。如果设置为为-1表示尽可能多地读取出来解码。参数firstline是如果后面行解码失败,只需要返回第一行。调用这个函数要注意是返回的大小等于size或者小于size,不会超过size的大小。
readline([size[, keepends]])
从输入流里读取一行数据并解码返回。
如果有给出读取大小size,那么就按这个大小到文件流里读取。
如果keepends为false,那么最后一行的结束符号会删除掉。
readlines([sizehint[, keepends]])
从输入流里读取所有行数据,并解码写到列表里返回。
如果有给出读取大小sizehint,那么就按这个大小到文件流里读取。
如果keepends为false,那么最后一行的结束符号会删除掉。
reset()
复位所有缓冲区。
4.2.1.4.3 StreamReaderWriter对象
类StreamReaderWriter是StreamReader和StreamWriter的组合类,它合并了流文件的读取和写入的功能。这样设计可以很方便地通过工厂函数lookup()来构造一个流对象。
class codecs.StreamReaderWriter(stream, Reader, Writer, errors)
构造一个StreamReaderWriter对象。参数stream是像文件类似的流对象。参数Reader和Writer可以是工厂函数,也可以是StreamReader和StreamWriter对象。
4.2.1.4.4 StreamRecoder对象
类StreamRecoder是实现从一种编码到另一种编码的转换,当在不同编码之间进行转换时比较有用。同时可以通过工厂函数lookup()来构造实例对象。
class codecs.StreamRecoder(stream, encode, decode, Reader, Writer, errors)
构造一个StreamRecoder对象,它实现两种转换方式:encode和decode工作在前端,而Reader和Writer是工作在后端,主要调用read()和writer()实现。通过此函数可以实现从Latin-1编码到UTF-8的编码进行相互转换。
参数stream是文件类似的对象。参数encode和decode是Codec的接口。参数Reader和Writer是流对象StreamReader和StreamWriter的接口。