python處理中文編碼問題總結
如何處理中文編碼的問題
python的UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xxx in position
這個錯誤是因為你程式碼中的某個字串使用了費ascii編碼的字元,也就是它代表的16進位制的編碼超過127。
解決這個問題可以使用下面的方法解決,其實就是設定預設的編碼。python 2.x的預設編碼是ascii,如果改為utf-8,就可以了。
import sys
reload( sys )
sys.setdefaultencoding('utf-8')
其實從python 3.0以後預設就用utf-8,就沒有這個問題了。
新手寫pyhton程式經常遇到編碼問題,其實是對py的編碼不熟悉,經常範小毛病,鬱悶好久。。。
今天終於搞懂的py的編碼。
1. pyhton的所有內建庫、方法接受的是unicode編碼的字串。
2. str.decode 函式就是轉成unicode編碼,所以能decode的字串傳級python的內建庫、函式都能正確執行。
3.問題在於這個decode函式解碼時到底要傳哪個引數:utf-8,gbk,gb2312……等N種編碼。引數不當,就會拋類似異常:
UnicodeDecodeError: ‘gbk’ codec can’t decode bytes in position 2-3: illegal multibyte sequence
UnicodeDecodeError: ‘utf8’ codec can’t decode bytes in position 0-1: invalid data
下面舉個例子:
#coding:utf-8
#指定本檔案編碼為utf8
import os
# 以下為示例程式碼,不一定能執行。隨意寫的,無編譯執行過。
# 例子以XP平臺為例,因為linux平臺編碼(UTF-8)與window平臺(GBK)不一樣。
# 假設D盤下面有很多中文名稱檔案
filelist = os.listdir(r"d:\\") # 此處返回的list中的中文是以GBK編碼的,你可以通過檢視cmd視窗屬性看到。
for path in filelist:
if os.path.isdir(path): continue
fp = open(path.decode("GBK" ) , 'rb') # 如果此處用 path.decode("UTF-8") 就會拋異常,原因是wind的dir命令返回的是GBK編碼
print len(fp.read())
fp.close()
filepath =r"d:\\中文檔案.doc" # 假設此文存在,記得要帶中文
fp = open(filepath.decode('utf-8'), "rb") #這裡使用utf8引數進行解碼,原因是檔案頭裡有句coding: utf-8
print len(fp.read())
fp.close()
path2 = u"d:\\中文檔案.doc" # 假如這裡有個u在前面,這個變數就是unicode編碼了,不用解碼。
fp = open(path2, 'rb')
print len(fp.read())
fp.close()
為什麼Python使用過程中會出現各式各樣的亂碼問題,明明是中文字元卻顯示成“\xe4\xb8\xad\xe6\x96\x87”的形式?
為什麼會報錯“UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)”?本文就來研究一下這個問題。
字串在Python內部的表示是unicode編碼,因此,在做編碼轉換時,通常需要以unicode作為中間編碼,即先將其他編碼的字串解碼(decode)成unicode,再從unicode編碼(encode)成另一種編碼。
decode的作用是將其他編碼的字串轉換成unicode編碼,如str1.decode(‘gb2312’),表示將gb2312編碼的字串str1轉換成unicode編碼。
encode的作用是將unicode編碼轉換成其他編碼的字串,如str2.encode(‘gb2312’),表示將unicode編碼的字串str2轉換成gb2312編碼。
因此,轉碼的時候一定要先搞明白,字串str是什麼編碼,然後decode成unicode,然後再encode成其他編碼
程式碼中字串的預設編碼與程式碼檔案本身的編碼一致。
如:s=’中文’
如果是在utf8的檔案中,該字串就是utf8編碼,如果是在gb2312的檔案中,則其編碼為gb2312。這種情況下,要進行編碼轉換,都需要先用decode方法將其轉換成unicode編碼,再使用encode方法將其轉換成其他編碼。通常,在沒有指定特定的編碼方式時,都是使用的系統預設編碼建立的程式碼檔案。
如果字串是這樣定義:s=u’中文’
則該字串的編碼就被指定為unicode了,即python的內部編碼,而與程式碼檔案本身的編碼無關。因此,對於這種情況做編碼轉換,只需要直接使用encode方法將其轉換成指定編碼即可。
如果一個字串已經是unicode了,再進行解碼則將出錯,因此通常要對其編碼方式是否為unicode進行判斷:
isinstance(s, unicode) #用來判斷是否為unicode
用非unicode編碼形式的str來encode會報錯
如何獲得系統的預設編碼?
#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()
該段程式在英文WindowsXP上輸出為:ascii
在某些IDE中,字串的輸出總是出現亂碼,甚至錯誤,其實是由於IDE的結果輸出控制檯自身不能顯示字串的編碼,而不是程式本身的問題。
如在UliPad中執行如下程式碼:
s=u"中文"
print s
會提示:UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)。這是因為UliPad在英文WindowsXP上的控制檯資訊輸出視窗是按照ascii編碼輸出的(英文系統的預設編碼是ascii),而上面程式碼中的字串是Unicode編碼的,所以輸出時產生了錯誤。
將最後一句改為:
print s.encode('gb2312')
則能正確輸出“中文”兩個字。
若最後一句改為:
print s.encode('utf8')
則輸出:\xe4\xb8\xad\xe6\x96\x87,這是控制檯資訊輸出視窗按照ascii編碼輸出utf8編碼的字串的結果。
unicode(str,’gb2312’)與str.decode(‘gb2312’)是一樣的,都是將gb2312編碼的str轉為unicode編碼
使用str.class可以檢視str的編碼形式
原理說了半天,最後來個包治百病的吧:)
#!/usr/bin/env python
#coding=utf-8
s="中文"
if isinstance(s, unicode):
#s=u"中文"
print s.encode('gb2312')
else:
#s="中文"
print s.decode('utf-8').encode('gb2312')
如何判斷字元str的編碼是什麼?
使用 chardet 可以很方便的實現字串/檔案的編碼檢測。尤其是中文網頁,有的頁面使用GBK/GB2312,有的使用UTF8,如果你需要去爬一些頁面,知道網頁編碼很重要的,雖然HTML頁面有charset標籤,但是有些時候是不對的。那麼chardet就能幫我們大忙了。
chardet例項
import urllib
rawdata = urllib.urlopen('http://www.google.cn/').read()
import chardet
chardet.detect(rawdata)
{'confidence': 0.98999999999999999, 'encoding': 'GB2312'}
chardet可以直接用detect函式來檢測所給字元的編碼。函式返回值為字典,有2個元數,一個是檢測的可信度,另外一個就是檢測到的編碼。
chardet 安裝
下載chardet後,解壓chardet壓縮包,直接將chardet資料夾放在應用程式目錄下,就可以使用import chardet開始使用chardet了。
或者使用setup.py安裝檔案,將chardet拷貝到Python系統目錄下,這樣你所有的python程式只要用import chardet就可以了。
python setup.py install
總結
儘量把所有的input 都decode成unicode。即 str.decode(‘utf-8’);
輸出時,再encode成所需的編碼格式
decode的作用是將其他編碼的字串轉換成unicode編碼,如str1.decode(‘gb2312’),表示將gb2312編碼的字串str1轉換成unicode編碼。
encode的作用是將unicode編碼轉換成其他編碼的字串,如str2.encode(‘gb2312’),表示將unicode編碼的字串str2轉換成gb2312編碼。