模块 codecs 提供接口转变数据编码,它常常和 Unicode 编码使用,但是也可以和其他编码一起使用。
Unicode 编码
Python 解释器 CPython 3.x 提供了两种字符串类型: text 和 byte string。bytes 是一个8位的字节序列,str是文本字符串,内部是一个 Unicode code points 序列。code point 值可以是2个或者4个字节,根据编译 Python 时给定的选项确定,所以说 Unicode 编码的字节长度是可变的。
当 str 打印时,根据内部的字节编码类型,把内部的 code point 转换为显示的字符,所以 Unicode 的数据需要根据字节编码转换为内部显示的字符。使用字节序列的 bytes 和 code point 是不一样的,它没有这种情况。
Unicode 最常用的编码类型是 UTF-8 和 UTF-16,它使用一个字节或者2个字节的序列表示每个 code point。也包括其他的编码,由其他语言使用,他们不只使用2个字节表示 code point。
编码
为了更好的理解编码类型,下面的例子使用不同的编码打印了相同的数据。首先定义了一个函数 to_hex() 返回数据的二进制表示。
执行:
函数 to_hex() 第一个参数是要打印的二进制数据,第二个参数指定每次打印多少个字节,字节之间按空格分隔。
下面的例子分别使用 utf-8 和 utf-16 编码同一个字符串,然后打印字节数据。
执行:
文件
编码和解码对于 IO 操作是非常重要的,读取和写入都必须要知道数据的编码。例如写入一个文件,Socket或者其他流,数据必须要有正确的编码。通常从一个字节流转为内部的字符串表示叫做解码,把内部数据转换为特定的字节流叫做编码。模块 codecs 提供了方法自动解码和编码数据,所以我们写应用时,常常可以忽略这些细节。
codecs 模块的 open() 函数可以指定特定的编码和文件工作。
执行:
本例中,使用命令行传入编码类型,然后使用 codecs.open() 函数写入指定编码的数据,最后打印了不同编码类型的数据。
字节顺序
类似 UTF-8 和 UTF-16 这种多字节的编码类型,常常在多个计算机之间传递数据的时候,需要注意字节顺序的问题。因为不同的计算机系统使用的字节顺序有可能不一样。这样的特性通常称为 endianness,通常会根据硬件结构,操作系统,应用开发者来决定。
多字节的编码类型根据字节开头的 BOM(byte-order marker)来确定字节顺序,codecs 定义了多个常量标识不同编码的 BOM 值。
执行:
字节顺序会由 codecs 模块自动确定,你也可以在编码的时候显示的指定。下面不使用系统的字节顺序,而使用自定义的字节顺序写入数据到文件。
执行:
本例中,文件开头写入了 bom marker,当读取文件的时候,文件内容多输出了 bom marker。要想只返回文件内容,读取的时候需要指定编码类型。
执行:
当不指定编码类型时,默认使用系统的内置编码类型。如果内置编码类型和文件实际的类型不一致,则触发异常 UnicodeDecodeError。
执行:
错误处理
当读取和写入文件时,使用正确的编码类型是至关重要的。如果读取文件时,指定的编码类型错误,则触发异常,就和上面遇到的一样。当使用错误的编码类型,写入数据到文件时,数据就会丢失。
codecs 提供了下面5种选项处理从字符串编码和从字节流解码遇到的问题。
strict 如果数据转换失败,则触发异常replace 把不能编码的数据替换掉ignore 忽略不能编码的数据xmlcharrefreplace XML 字符backslashreplace 转义序列
下面的例子,试图把一个 Unicode 编码的数据写入到 ASCII 流的文件中,触发不同的错误处理方式。
执行:
正如上面所说,错误处理选项使用 strict 触发异常,replace 替换不能编码的字符,ignore 忽略。
编码转换
虽然大部分程序都使用 str 处理数据,而编码解码数据只是 IO 的一部分。有时候也需要转换编码格式。EncodedFile() 接收一个字节流和两个编码参数,把数据从一个编码类型转换为另一个。
执行:
本例把 utf-8 编码类型转换为 utf-16。
留言与评论(共有 0 条评论) |