python标准库之字符编码详解

时间:2023-03-08 20:13:32
python标准库之字符编码详解

codesc官方地址:https://docs.python.org/2/library/codecs.html

相关帮助:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html

#python标准库(英文地址:)http://www.ask3.cn/ebook/docspy3zh/library/index.html

unicode入门:

cpython2.xz支持2种类型字符串处理文本数据,老式的str实例使用单个8位字节表示字符串字符(ascii码),与之不同的unicode串在内部作为一个unicode码点(codepoint)序列来管理,码点值分别保存为2个或者4个字节序列,这取决于编译python时指定的选项,unicode和str都派生一个共同基类,并支持类似的api.

输入unicode串时,会使用某种标准机制编码,使得以后可以将这个字节序列重构为同样的文本串,编码值的字节不一定与码点值完全相同,编码只是定义了在2个值集之间转换的一种方式,读取unocide数据时还需要知道编码,这样才能接到字节转换为unicode类使用内部表示!

西方语言最常用的编码是utf-8 utf-16这2种编码 分别使用单字节和2字节值序列表示各个码点,对于其他语言,由于大多数字符由走过个字节码点表示,所以使用其他编码来存储可能更为高效

#注意:unicode论坛:http://www.unicode.org/ 或者请看<the python unicode howto>书籍信息

#编码

要了解编码,最好的方法就是采用不同方式对相同串进行编码,并查看所生成字节序列的区别

例子:

import binasciidef to_hex(t,nbytpes):    item=nbytpes*2    hex1=binascii.hexlify(t)    return ' '.join(hex1[s:s+item]for s in xrange(0,len(hex1),item))print to_hex('abcdef',1)print to_hex('abcdef',2)#这个函数使用binascii得到输入字节码的十六进制,在返回这个值之前每隔nbytpes字节就插入一个空格

#第一个编码例子首先使用uncidoe类的原始表示打印文本pi:π,π(3.14)字符替换为unicode码点的表达式\u03c0,接下来使用utf-8 utf-16,得到十六进制text=u'pi:,π'print 'raw  :',repr(text)print 'utf-8:{0} and utf-16{1}'.format(to_hex(text.encode('utf-8'),1),to_hex(text.encode('utf-16'),2))#对于一个unicode串编码 的结果是一个str对象

#给定一个编码字节序列(作为一个str实例),decode()方法会将其转换为码点,并作为一个unicode实例返回转换后序列en=text.encode('utf-8')de=en.decode('utf-8')print 'original:',repr(text)print 'en:',to_hex(en,1),type(en)print 'de:',repr(de),type(de)#注意:解释器启动过程中(即加载site时)会设置默认编码,关于默认编码设置的描述,可以参考sys部分(或者文档)

#处理文件
"""处理i/o操作时,编码和解码字符串尤其重要,否认是写入一个文件,一个套接字还是另外一个流,数据都必须使用适当的编码,一般来讲,所有文本数据在读取时都需要从其字节表示解码,写时则需要从内部值 编码为一种特定表示,一种程序可以地编码和解码数据,但是取决于手忙脚乱的编码,是确定是否已读取足够的字节以便充分解码数据,这一点可能并不容易。codes提供了一些类来管理数据的编码和解码,所以应用不需要做这个工作codes提供了最简单的接口可以来替代open()内置函数,新版本函数和内置函数做法相信,不过增加了2个参数来指定编码和所需的错误处理技术"""import sys,codecsen=sys.argv[0]filename=en+'.txt'print 'writing to:',filenamewith codecs.open(filename,mode='wt',encoding=en)as f:    f.write(u'pi:\u03c0')n={''utf-8:1,'utf-16':2,'utf-32':4}.get(en,1)print 'file contents:'with open(filename,mode='rt')as f:   print to_hex(f.read(),n)#这个例子首先从一个unicode串开始(包括pai的码点),并使用命令行指定指定的编码将文件保存到一个文件中使用open()读取数据很简单,但提前是需要知道它的编码,才能正确的建议解码器,尽管有些数据格式(如;xml)会指定编码作为文件一部分,但是通常都要由应用特定来管理,codecs只是取一个编码参数,并假设这个编码是正确的.
en=sys.argv[0]filename=en+'.txt'print 'writing to:',filename
with codecs.open(filename,mode='wt',encoding=en)as f:
  print repr(f.read())

字节顺序

多字节编码utf - 16和utf - 32等问题 不同的计算机系统之间传输数据,通过 直接复制文件或网络通信。 不同的 系统使用不同的排序的高和低字节顺序。 这 数据的特点,被称为它的字节顺序,取决于 等因素的硬件架构和选择 操作系统和应用程序开发人员。 并不总是有一种方法 提前知道使用什么字节顺序对于一个给定的数据集,所以 包括一个多字节编码的字节顺序标记(BOM)的 前几个字节的编码输出。 例如,定义utf - 16 的方式0 xfffe和0 xfeff无效字符,和可以 被用来表示字节顺序。编解码器定义常量 使用的字节顺序标记utf - 16和utf - 32。

for name in [ 'BOM', 'BOM_BE', 'BOM_LE',
              'BOM_UTF8',
              'BOM_UTF16', 'BOM_UTF16_BE', 'BOM_UTF16_LE',
              'BOM_UTF32', 'BOM_UTF32_BE', 'BOM_UTF32_LE',
              ]:
    print '{:12} : {}'.format(name, to_hex(getattr(codecs, name), 2))

取决于当前系统固有字节序,bom,bom_utf16,bom_utf-32会自动设置为适合的大端(big-endian)或者小端(little-endian)值#信息库:
BOM          : fffe
BOM_BE       : feff
BOM_LE       : fffe
BOM_UTF8     : efbb bf
BOM_UTF16    : fffe
BOM_UTF16_BE : feff
BOM_UTF16_LE : fffe
BOM_UTF32    : fffe 0000
BOM_UTF32_BE : 0000 feff
BOM_UTF32_LE : fffe 0000

可以由codecs中解码器自动检测和处理字节序,不过编码时也可以地指定字节序.#下面这个a.py文件,代码如下:
if codecs.BOM_UTF16 == codecs.BOM_UTF16_BE:
    bom = codecs.BOM_UTF16_LE
    encoding = 'utf_16_le'
else:
    bom = codecs.BOM_UTF16_BE
    encoding = 'utf_16_be'

print 'Native order  :', to_hex(codecs.BOM_UTF16, 2)
print 'Selected order:', to_hex(bom, 2)

# Encode the text.
encoded_text = u'pi: \u03c0'.encode(encoding)
print '{:14}: {}'.format(encoding, to_hex(encoded_text, 2))

with open('non-native-encoded.txt', mode='wb') as f:
    # Write the selected byte-order marker.  It is not included in the
    # encoded text because we were explicit about the byte order when
    # selecting the encoding.
    f.write(bom)
    # Write the byte string for the encoded text.
    f.write(encoded_text)上面a.py这部分代码首先得出内置字节码,然后显示地使用候选形式,以方便下一个例子读取时自动检测字节序.a.py打开文件时没有指定序,所以解码器会使用文件前2个字节中的bom来确定字节序.
with open('non-native-encoded.txt', mode='rb') as f:
    raw_bytes = f.read()

print 'Raw    :', to_hex(raw_bytes, 2)

# Re-open the file and let codecs detect the BOM
with codecs.open('non-native-encoded.txt', mode='rt', encoding='utf-16') as f:
    decoded_text = f.read()

print 'Decoded:', repr(decoded_text)

#由于文件前2个字节用于字节序检测,所以它们并不包含在read()返回数据中

##错误处理

前面几节指出了需要知道的编码 阅读和写作时使用Unicode文件。 设置编码 正确是很重要的,原因有两个。 如果编码配置 错误的同时读取一个文件,数据将被解释 错了,可能会损坏或者无法解码。 并不是所有的Unicode 字符可以用在所有的编码,因此,如果错了 使用编码在写将生成一个错误和数据 是输了。

编解码器使用相同的五个错误处理选项 提供的编码()的方法Unicodedecode()的方法STR

strict Raises an exception if the data cannot be converted.提出了一个异常如果数据不能转换。
replace Substitutes a special marker character for data that cannot be encoded.替代一个特殊的标记字符数据,不能编码。
ignore Skips the data.跳过数据。
xmlcharrefreplace XML character (encoding only)XML字符(编码)
backslashreplace escape sequence (encoding only)转义序列(编码)

编码错误

最常见的错误条件是收到UnicodeEncodeError当你写 Unicode数据到一个ASCII输出流,如一个常规文件或sys.stdout。 可以使用这个示例程序 尝试不同的错误处理模式。

import codecs
import sys

error_handling = sys.argv[1]

text = u'pi: \u03c0'

try:
    # Save the data, encoded as ASCII, using the error
    # handling mode specified on the command line.
    with codecs.open('encode_error.txt', 'w',
                     encoding='ascii',
                     errors=error_handling) as f:
        f.write(text)

except UnicodeEncodeError, err:
    print 'ERROR:', err

else:
    # If there was no error writing to the file,
    # show what it contains.
    with open('encode_error.txt', 'rb') as f:
        print 'File contents:', repr(f.read())要确保一个应用程序地为所有I/O操作设置正确编码,strict模式最安全,但是产生一个异常时,可能导致程序崩溃.

一些其他的错误模式更加灵活。 例如,取代确保没有错误,为代价的 可能失去的数据不能被转换为所请求的 编码。 pi仍不能编码的Unicode字符 ASCII,而是提高异常字符被替换 与吗?在输出。
完全跳过问题数据,使用忽略。 任何数据, 不能编码只是丢弃。

有两种无损的错误处理选项,这两个替换 另一种表示形式的特性定义的标准 独立于编码。xmlcharrefreplace使用XML 作为替代字符引用(字符引用的列表 在W3C中指定吗XML字符实体定义)。

其他无损的错误处理方案backslashreplace哪一个 产生输出格式打印时喜欢你得到的价值repr()Unicode对象。 Unicode字符 取而代之的是\ u紧随其后的是十六进制值的代码 点。

解码错误

还可以看到错误解码数据时,特别是 使用错误的编码。

error_handling = sys.argv[1]

text = u'pi: \u03c0'
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, err:
        print 'ERROR:', err
    else:
        print 'Read         :', repr(data)

与编码,严格的错误处理模式提出了一个例外 如果不能正确解码的字节流。 在这种情况下,UnicodeDecodeError结果 试图将utf - 16 BOM的一部分转换为字符使用 utf - 8解码器。

切换到忽略导致译码器跳过无效 字节。 结果仍然是不期望是什么,不过, 它包括嵌入式空字节。

在取代无效的字节替换模式\ uFFFD, 官方Unicode替换字符,它看起来像一个钻石 包含白色与黑色背景问号(�)。更多请看:http://pymotw.com/2/codecs/ (这个是标准库的)官方地址:https://docs.python.org/2/library/codecs.html