當前位置:
首頁 > 知識 > python 字元編碼處理總結

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的字元引用。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!

TAG: |