• Python 字符编码处理总结


    Python中经常遇到这样那样的字符编码问题,尤其在处理网页源码时(特别是爬虫中):

    UnicodeDecodeError: ‘XXX' codec can't decode bytes in position 12-15: illegal multibyte...

    每次看到上面这段文字的时候,感觉整个世界都昏暗了,然后就只能各种搜索找资料,过后就忘了。下次遇到时就让世界再昏暗一次。为了彻底解决这个拦路虎,今天咱们就好好的来唠嗑唠嗑。

    下面以汉字'哈'来解释作示例解释所有的问题,汉字“哈”的各种编码如下:

    1 UNICODE(UTF8-16): 0xC854

    2 UTF-8: 0xE59388

    3 GBK: 0xB9FE

    除此之外还有如gb2312, big5等。例如一些含有繁体字的页面,比如www.google.com.hk首页中用的就是big5码,

    不知道港台的码农同时处理简体字繁体字是不是更郁闷(笑脸)

    处理解决

    首先,在python中提到unicode,一般指的是unicode对象,例如'哈哈'的unicode对象为u'u54c8u54c8'

    而str是一个字节数组,这个字节数组表示的是对unicode对象编码后(如utf-8、gbk、cp936、GB2312)的存储的格式,这里它仅是一个字节流,没有其它的含义,如果你想使这个字节流显示的内容有意义,就必须用正确的编码格式,解码显示。

    例如:(注意是在windows下)

    s = u'哈哈'

    s_utf8 = s.encode('utf-8')

    pirnt s_utf8

    >>> 鍝堝搱

    悲剧...

    s_utf8这时实际上是'xe5x93x88xe5x93x88'

    而下面的代码才可以正常显示:

    s_gdb = s.encode('gbk') # s_gdk 这时是'xb9xfexb9xfe'

    print s_gbk

    >>> 哈哈 #正常了

    因为print语句它的实现是将要输出的内容传 送了操作系统,操作系统会根据系统的编码对输入的字节流进行编码,这就解释了utf-8格式的字符串“哈哈”,输出的是“鍝堝搱”,因为 'xe5x93x88xe5x93x88'用GB2312去解释,其显示的出来就“鍝堝搱”。

    这里再强调一下,str记录的是字节数组,只是某种编码的存储格式,至于输出到文件或是打印出来是什么格式,完全取决其解码的编码将它解码成什么样子。

    str和unicode对象的转换,通过encode和decode实现,具体使用如下:再次强调windows下:

    s = '哈哈'

    print s.decode('gbk').encode('utf-8')

    >>> 鍝堝搱

    反之亦然,有兴趣可以尝试其他转换

    有时当我们遇到把s(gbk字符串)直接编码成utf-8的时候,将抛出异常,但是通过调用如下代码:

    import sys

    reload(sys)

    sys.setdefaultencoding('gbk')

    后就可以转换成功,为什么呢?

    在python中str和unicode在编码和解码过程中,如果将一个str直接编码成另一种编码,会先把str解码成unicode,采用默认编码,一般默认编码是anscii,所以在上面示例代码中第一次转换的时候会出错,

    当设定当前默认编码为'gbk'后,就不会出错了。至于reload(sys)是因为Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法,我们需要重新载入。一般不推荐这样使用。本来reload都是应该避免使用的函数。

    对于操作不同文件的编码格式的文件,也会遇到这样的问题

    建立一个文件test.txt,文件格式用ANSI,内容为:

    abc中文

    然后用python来读取

    # coding=gbk

    print open("Test.txt").read()

    结果:abc中文

    把文件格式改成UTF-8:

    结果:abc涓�枃,显然,这里需要解码:

    # coding=gbk

    import codecs

    print open("Test.txt").read().decode("utf-8")

    结果:abc中文

    上面的test.txt我是用Editplus来编辑的,但当我用Windows自带的记事本编辑并存成UTF-8格式时,

    运行时报错:

    Traceback (most recent call last):

    File "ChineseTest.py", line 3, in

    print open("Test.txt").read().decode("utf-8")

    UnicodeEncodeError: 'gbk' codec can't encode character u'ufeff' in position 0: illegal multibyte sequence

    原来,某些软件,如notepad,在保存一个以UTF-8编码的文件时,

    会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。

    因此我们在读取时需要自己去掉这些字符,python中的codecs module定义了这个常量:

    # coding=gbk

    import codecs

    data = open("Test.txt").read()

    if data[:3] == codecs.BOM_UTF8:

    data = data[3:]

    print data.decode("utf-8")

    结果:abc中文

    最后,有些时候编码搞对了,但是遇到了非法字符,比如产生字符串的来源发生错误,引入了错误值等,这时再次遇到异常

    例如:全角空格往往有多种不同的实现方式,比如xa3xa0,或者xa4x57,

    这些字符,看起来都是全角空格,但它们并不是“合法”的全角空格

    真正的全角空格是xa1xa1,因此在转码的过程中出现了异常。

    而之前在处理新浪微博数据时,遇到了非法空格问题导致无法正确解析数据。

    解决办法:

    将获取的字符串strTxt做decode时,指明ignore,会忽略非法字符,

    当然对于gbk等编码,处理同样问题的方法是类似的

    strTest = strTxt.decode('utf-8', 'ignore')

    return strTest

    默认的参数就是strict,代表遇到非法字符时抛出异常;

    如果设置为ignore,则会忽略非法字符;

    如果设置为replace,则会用?号取代非法字符;

    如果设置为xmlcharrefreplace,则使用XML的字符引用。

  • 相关阅读:
    LeetCode Combination Sum III
    LeetCode Contains Duplicate
    CSRF & CORS
    LeetCode Kth Largest Element in an Array
    Maven 使用 Nexus 内部库 代理
    可重定位目标文件
    过程(栈帧结构是干货)
    控制语句(if-else+循环+switch)汇编规则
    程序编码(机器级代码+汇编代码+C代码+反汇编)
    转移指令jmp和跳转指令call
  • 原文地址:https://www.cnblogs.com/kolane/p/11538122.html
Copyright © 2020-2023  润新知