在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的接口。