IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]4.2.1 Codec基类

    caimouse发表于 2015-11-01 09:33:49
    love 0

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

     



    蔡军生  QQ:9073204  深圳



沪ICP备19023445号-2号
友情链接