1.基本概念
字符集(Characterset)
解釋:文字和符合的總稱
常見字符集:
Unicode字符集
ASCII字符集(Unicode子集)
GB2312字符集
編碼方法(Encoding)
解釋:將字符對應到字節的方法,部分字符集和編碼方法名稱一樣。
常見編碼方法:
UTF-8:可對Unicode字符進行編碼
GB2312
ASCII
編碼(Encode)
解釋:將字符集中字符按照一定規則轉換成字節
解碼(Decode)
解釋:與編碼相反,將字節轉換為字符集中的字符
字符集與編碼方法的關系
每個字符集都有對應的編碼方法
一種字符集可能有多種編碼方法
不同的編碼方法得到的字節不同,占用存儲空間也不一樣
例如Unicode字符可以使用UTF-8/ASCII/GBK等方法編碼
Unicode字符集包含世界上大部分字符,很多其他字符集有的字符它都有,是他們的超集
大部分字符集可以理解為Unicode的子集
實際上,除了Unicode之外所謂的字符集主要是對Unicode部分字符編碼而已(定義編碼方式)
一種編碼不必支持Unicode的所有字符(通常把它能支持的那部分稱為它的字符集)
2.關于編碼的錯誤和解決方法
在開發過程中,我們所接觸的字符集大多都是Unicode,大部分報錯都是關于編碼和解碼的。
2.1.編碼錯誤UnicodeEncodeError
2.1.1.錯誤分析
導致該錯誤的原因通常是編碼方法支持的Unicode字符不全;在工作中,你寫了一個txt中文文檔,想用ascii編碼去保存這個文件,就會報這種錯誤。
錯誤復現:
我們知道ascii不支持字符中,那我們用ascii編碼方法對Unicode碼中進行編碼:
#-*-encoding:utf-8-*-
u"中".encode(encoding='ascii')
報錯如下:
UnicodeEncodeError:'ascii'codeccan'tencodecharacter'\u4e2d'inposition0:ordinalnotinrange(128)
這是一個UnicodeEncodeError類型的錯誤,提示無法使用指定的編碼方法對字符進行編碼,報錯提示中可以得到3個信息:
當前使用的是acsii編碼方法
被編碼的字符是'\u4e2d'
ascii編碼方法能支持的字符有128個
有時候我們還可以利用這個提示查看編碼方法支持的字符個數:
#-*-encoding:utf-8-*-
u"中".encode(encoding='iso-8859-1')
報錯:
UnicodeEncodeError:'latin-1'codeccan'tencodecharacter'\u4e2d'inposition0:ordinalnotinrange(256)
通過報錯提示可以看出iso-8859-1能編256個字符。
接著,我們來看下用支持中文的utf-8編碼方法進行編碼能得到什么結果:
#-*-encoding:utf-8-*-
s=u"中".encode(encoding='utf-8')
print("s:",s)
print("s==中?",s=='中')
print("typeofs:",type(s))
print("str==bytes?",bytes==type(s))
輸出:
('s:','\xe4\xb8\xad')
('s==\xe4\xb8\xad?',True)
('typeofs:',)
('str==bytes?',True)
從輸出的結果可以得到:
-編碼得到的對象跟我們直接定義的字符串是一樣的,都是str
-str就是bytes(python中)
2.1.2.解決方法
UnicodeEncodeError是說編碼方法支持的字符不全,而UTF-8編碼就能很好地對Unicode編碼,所以只要把編碼方法指定為utf-8就可以了。
在python2中:
如果你調用encode方法但沒有指定encoding參數,那很可能使用了系統默認的參數,就像:
#-*-encoding:utf-8-*-
importsys
print"defaultencodingis%s."%sys.getdefaultencoding()
u'中'.encode()
輸出:
defaultencodingisascii.
UnicodeEncodeError:'ascii'codeccan'tencodecharacteru'\u4e2d'inposition0:ordinalnotinrange(128)
可以手動指定encoding參數,也可以修改python默認編碼方法:
#-*-encoding:utf-8-*-
importsys
reload(sys)
sys.setdefaultencoding('utf-8')#必須在reload之后調用
printu'中'.encode()
在python3中:
在python3中你很難看到UnicodeEncodeError了,因為python3的默認編碼就是utf-8,而Unicode字符都可以用utf-8編碼方法編碼。
2.2.編碼錯誤UnicodeDecodeError
2.2.1.錯誤分析
導致該錯誤的原因是使用了錯誤的解碼方式把字節數據還原成字符。例如在工作中,有一個utf-8生成中文文檔,我們選擇用ascii編碼解碼,就會報這個錯。
錯誤復現:
我們知道python中字符串和字節是一樣,我們可以定義一個中文字符串,通過ascii來解碼生成Unicode,復現這個錯誤:
#-*-encoding:utf-8-*-
print'中'.decode(encoding='ascii')
輸出:
UnicodeDecodeError:'ascii'codeccan'tdecodebyte0xe4inposition0:ordinalnotinrange(128)
注意,這是一個UnicodeDecodeError錯誤,區別于編碼錯誤UnicodeEncodeError,它提示無法把字節0xe4(實際上中對應三字節,0xe4是第一個)解碼成Unicode。0xe4轉換為10進制是228,已經超過127了,所以ascii無能力了。
2.2.2.解決方法
我們需要知道生成字節的編碼方式才能進行還原,就好像對一個文件進行了加密,必須得知道加密的密碼才能把文件還原,而解碼方式(或者稱為編碼)就是那個密碼。所以不管是python2還是python3直接去修改默認編碼為UTF-8不一定能解決問題,具體的方法有兩種:
通過源碼找到解碼失敗的字節是使用那種編碼生成的
對報錯的字節數據使用各種常見的編碼進行解碼,觀察哪一種是正確的
以一個例子來說明為什么直接設置默認編碼為UTF-8不能有效解決UnicodeDecodeError問題
python文件頭指定了編碼為,在聲明字符串時候將會使用指定的編碼轉換為字節:
#-*-encoding:GBK-*-
s="張"
print("sis",s)
s_unicode=u'張'
print("encodingwithGBKis",s_unicode.encode("GBK"))
print("encodingwithUTF-8is",s_unicode.encode("UTF-8"))
輸出:
('sis','\xd5\xc5')
('encodingwithGBKis','\xd5\xc5')
('encodingwithUTF-8is','\xe5\xbc\xa0')
在文件頭中指定了GBK編碼后默認情況下字符張就會被編碼為\xd5\xc5,這與我們手動用GBK編碼得到結果一致,而使用utf-8編碼得到的是3個字節的數據\xe5\xbc\xa0(使用了更多的存儲空間)。
例子開始了,在python2中將一個dict轉換成json:
#-*-encoding:GBK-*-
importjson
d={'name':"張",'sex':u'man'}
print(json.dumps(d))
輸出:
UnicodeDecodeError:'utf8'codeccan'tdecodebyte0xd5inposition0:invalidcontinuationbyte
錯誤說無法使用utf-8解碼0xd5,0xd5也就是GBK中的張,我們知道這個字節是用GBK生成的,這個時候可以設置json.dumps的encoding參數解決:
#-*-encoding:GBK-*-
importjson
d={'name':"張",'sex':u'man'}
print(json.dumps(d,encoding='gbk'))
修改一下代碼,繼續使用我們熟悉的utf-8編碼來執行:
#-*-encoding:utf-8-*-
importjson
d={'name':"張",'sex':u'man'}
print(json.dumps(d,encoding='utf-8'))
輸出:
{"name":"\u5f20","sex":"man"}
發現name是unicode,使用ensure_ascii=False,不強制轉換成ascii:
#-*-encoding:utf-8-*-
importjson
d={'name':"張",'sex':u'man'}
print(json.dumps(d,encoding='utf-8',ensure_ascii=False))
輸出:
File"/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py",line251,indumps
sort_keys=sort_keys,**kw).encode(obj)
File"/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py",line210,inencode
return''.join(chunks)
UnicodeDecodeError:'ascii'codeccan'tdecodebyte0xe5inposition1:ordinalnotinrange(128)
納尼,文件頭也是utf-8,也指定了utf-8怎么還是報錯?錯誤提示用ascii去解碼0xe5字節,在上面的代碼輸出中可以知道0xe5是utf-8對字符張編碼的第一個字節,報錯的原因是用ascii去解析utf-8生成的字節了。我們并沒有設置哪個地方使用ascii解碼,應該是系統默認的編碼,嘗試設置系統默認編碼再執行:
#-*-encoding:utf-8-*-
importsys
reload(sys)
sys.setdefaultencoding('utf-8')
importjson
d={'name':"張",'sex':u'man'}
print(json.dumps(d,encoding='utf-8',ensure_ascii=False))
輸出:
{"name":"張","sex":"man"}
3.總結
3.1.python2和python3對字符串的處理區別
Python2
默認編碼是ascii
Python3
importsys;sys.setdefaultencoding('utf-8')
3.2.為什么不全用UTF-8編碼?
UTF-8包含的字符更多,占用的內存和磁盤空間也更大,比如對漢字張,utf-8是3個字節,gbk是2個字節。
3.3.如何快速解決UnicodeEncodeError錯誤?
python3中基本不會出現,python2中嘗試設置默認編碼為utf-8。
3.4.快速解決UnicodeDecodeError?
需要知道出錯的字節是使用哪種編碼方式生成的,然后嘗試把默認編碼設置成這種。
以上內容為大家介紹了解決Python編碼問題,希望對大家有所幫助,如果想要了解更多Python相關知識,請關注IT培訓機構:千鋒教育。http://www.dietsnews.net/