問題
在平時(shí)工作中,遇到了這樣的錯誤:
UnicodeDecodeError: 'ascii' codec can't decode byte
想必大家也都碰到過,很常見 。于是決定對python的編碼做一個整理和學(xué)習(xí)。
基礎(chǔ)知識
在python2.x中,有兩種數(shù)據(jù)類型,unicode和str,這兩個都是basestring的子類
>>> a = '中' >>> type(a)>>> isinstance(a,basestring) True >>> a = u'中' >>> type(a) >>> isinstance(a,basestring) True
兩者的區(qū)別,概括來講,str是字節(jié)串,由unicode經(jīng)過編碼(encode)后的字節(jié)組成的(好比與python3.x的byte);unicode是對象,才是真正意義上的字符串,由字符組成
>>> a='中文' >>> len(a) 6 >>> repr(a) "'\\xe4\\xb8\\xad\\xe6\\x96\\x87'" >>> b=u'中文' >>> len(b) 2 >>> repr(b) "u'\\u4e2d\\u6587'"
控制臺和腳本
在linux下的python控制臺執(zhí)行以下命令,所得的結(jié)果和執(zhí)行腳本是不同的
>>> a = u'中文' >>> repr(a) "u'\\xe4\\xb8\\xad\\xe6\\x96\\x87'" >>> b = unicode('中文','utf-8')b) >>> repr(b) "u'\\u4e2d\\u6587'"
可以看到,u'中文'初始化的對象a不是我們所期望的,那究竟是什么原因呢?
將python看成是一根管子,管子里頭處理的中間過程都是使用unicode的。入口處,全部轉(zhuǎn)成unicode;出口處,再轉(zhuǎn)成目標(biāo)編碼(當(dāng)然,有例外,處理邏輯中要用到具體編碼的情況)。
在控制臺執(zhí)行命令a = u'中文',可以將解釋為命令,a = ‘中文'.decode(encode),從而到到unicode對象a。那么這里的encode是什么呢?對于控制臺來說,就是標(biāo)準(zhǔn)輸入,即sys.stdin.encoding
>>> sys.stdin.encoding 'ISO-8859-1'
我的這邊控制臺默認(rèn)的編碼是ISO-8859-1,故a = u'中文' <=> a = '中文'.decode('ISO-8859-1')
這里的'中文'是控制臺理解的,即使根據(jù)終端編碼方式編碼后的字節(jié)碼,對于utf-8編碼的終端,'中文'='\\xe4\\xb8\\xad\\xe6\\x96\\x87'
>>> a='中文'.decode('ISO-8859-1') >>> repr(a) "u'\\xe4\\xb8\\xad\\xe6\\x96\\x87'"
那如何修改此編碼值呢,設(shè)置為什么呢?在linux環(huán)境中設(shè)置環(huán)境變量方法如下,具體設(shè)置什么只要與終端編碼方式一直即可
export PYTHONIOENCODING=UTF-8
總結(jié)
重新回到最初的那個問題,造成問題的原因是沒有搞清楚unicode和str的區(qū)別,將兩者進(jìn)行了混用。
>>> a = '中文' >>> a.encode('gbk') Traceback (most recent call last): File "", line 1, in UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
以上的對象a其實(shí)是str,即字節(jié)碼,若終端是utf-8編碼的話,那么a就是用utf-8 encode的字節(jié)碼。a.encode('gbk') 等價(jià)于a.decode(encoding).encode('gbk'),即先將字節(jié)碼解碼為unicode字符,然后再encode為字節(jié)碼。unicode對象作為中轉(zhuǎn)站。那么這里的encoding是什么呢?
>>> import sys >>> sys.getdefaultencoding() 'ascii'
默認(rèn)是ascii,這正是錯誤為什么報(bào)無法用ascii解碼的原因
>>> reload(sys)>>> sys.setdefaultencoding('utf-8') >>> a = '中文' >>> repr(a) "'\\xe4\\xb8\\xad\\xe6\\x96\\x87'" >>> a.encode('gbk') '\xd6\xd0\xce\xc4'
將默認(rèn)編碼改為utf-8,即可。不鼓勵對str使用encode方法,因?yàn)槠渲须[式對str進(jìn)行了解碼。decode只對str,encode只對unicode,一切decode/encode都顯示指定編碼方式。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
