開發(fā)經(jīng)常會(huì)遇到各種字符串編碼的問(wèn)題,,例如報(bào)錯(cuò)SyntaxError: Non-ASCII character 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) ,,又例如顯示亂碼。 由于之前不知道編碼的原理,,遇到這些情況,,就只能不斷的用各種編碼decode和encode。,。,。。,。 今天整理一個(gè)python中的各種編碼問(wèn)題的原因和解決方法,,以后遇到編碼問(wèn)題,就不會(huì)像莽頭蒼蠅一樣,,到處亂撞了,。
下面的python環(huán)境都是在2.7,聽說(shuō)在3.X中已經(jīng)沒有編碼的問(wèn)題了,,因?yàn)樗械淖址际莡nicode了,,之后裝個(gè)3.X試一下。
如果不知道什么是decode和encode,,建議先看一下:這里
一,、encoding的作用
1.在python文件中,如果有中文,就一定要在文件的第一行標(biāo)記使用的編碼類型,,例如#encoding=utf-8 ,就是使用utf-8的編碼,,這個(gè)編碼有什么作用呢?會(huì)改變什么呢,? demo1.py
# encoding=utf-8test='測(cè)試test'print type(test)print repr(test)
輸出:
<type 'str'>'\xe6\xb5\x8b\xe8\xaf\x95test'
我們通過(guò)print把一個(gè)變量輸出到終端的時(shí)候,,IDE或者系統(tǒng)一般都會(huì)幫我們的輸出作轉(zhuǎn)換,例如中文字符會(huì)轉(zhuǎn)成中文,,所以就看不到變量的原始內(nèi)容,。 repr函數(shù)可以看這個(gè)變量的給python看的形式,也就是看到這個(gè)變量的原始內(nèi)容 從上面的輸出可以看到test變量的str類型,,它的編碼是utf-8的(怎么知道是utf-8,,請(qǐng)看第三部分),也就是的encoding類型 如果我們把encoding改為gbk demo2.py
# encoding=gbktest='測(cè)試test'print type(test)print repr(test)
輸出
<type 'str'>'\xb2\xe2\xca\xd4test'
這樣test的編碼類型就變?yōu)間bk了,。 所以這個(gè)encoding會(huì)決定在這個(gè)py文件中定義的字符串變量的編碼方式,。 而如果一個(gè)變量是從其他py文件導(dǎo)入,或者從數(shù)據(jù)庫(kù),,redis等讀取出來(lái)的話,,它的編碼又是怎樣的? a.py
# encoding=utf-8test='測(cè)試test'
b.py
# encoding=gbkfrom a import testprint repr(test)
輸出
'\xe6\xb5\x8b\xe8\xaf\x95test'
a.py中定義test變量,,a.py的編碼方式是utf-8,b.py的編碼方式是gbk,b從a中導(dǎo)入test,,結(jié)果顯示test依然為utf-8編碼,也就是a.py的編碼 所以encoding只會(huì)決定本py文件的編碼方式,,不會(huì)影響導(dǎo)入的或者從其他地方讀取的變量的編碼方式
二,、常見報(bào)錯(cuò)codec can't encode characters 的原因
python的程序經(jīng)常會(huì)報(bào)錯(cuò)codec can't encode characters 或codec can't decode characters
在python中定義一個(gè)字符串,
import sysprint sys.getdefaultencoding() # 輸出 asciiunicode_test=u'測(cè)試test'print repr(str(unicode_test))
上面的代碼會(huì)報(bào)錯(cuò)
'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
除了str方法外,,如果操作兩個(gè)都有中文的字符串,,也會(huì)報(bào)錯(cuò),但是只有其中一個(gè)有中文,,卻不會(huì)報(bào)錯(cuò)
unicode_test = u'測(cè)試test%s{0}'print '%stest' % unicode_test # 不會(huì)報(bào)錯(cuò)print '%s測(cè)試' % unicode_test #會(huì)報(bào)錯(cuò)print unicode_test % 'test' #不會(huì)報(bào)錯(cuò)print unicode_test % '測(cè)試' #會(huì)報(bào)錯(cuò)print unicode_test.format('test') #不會(huì)報(bào)錯(cuò)print unicode_test.format('測(cè)試') #會(huì)報(bào)錯(cuò)print unicode_test.split('test') #不會(huì)報(bào)錯(cuò)print unicode_test.split('測(cè)試') #報(bào)錯(cuò)print unicode_test + 'test' #不會(huì)報(bào)錯(cuò)print unicode_test + '測(cè)試' #會(huì)報(bào)錯(cuò)
為什么會(huì)這樣,? 這原因下面再解答,這里先列出這個(gè)報(bào)錯(cuò)的解決方法: 解決方法是:把系統(tǒng)的默認(rèn)編碼設(shè)置為utf-8
import sysreload(sys)sys.setdefaultencoding('utf-8')print sys.getdefaultencoding()unicode_test=u'測(cè)試test'
demo3.py # encoding=utf-8 import sys reload(sys) sys.setdefaultencoding('utf-8') unicode_test=u'測(cè)試test' utf8_test='測(cè)試test' gbk_test=unicode_test.encode('gbk')
#合并unicode和utf-8merge=unicode_test+utf8_testprint type(merge)print repr(merge)#合并unicode和gbkmerge=unicode_test+gbk_testprint type(merge)print repr(merge)print merge#合并utf-8和gbkmerge=utf8_test+gbk_testprint type(merge)print repr(merge)print merge
這里定義三個(gè)分別是unicode,,utf-8和gbk編碼的字符串,,unicode_test,utf8_test和gbk_test 1.合并unicode和utf-8的時(shí)候,輸出:
<type 'unicode'>u'\u6d4b\u8bd5test\u6d4b\u8bd5test'
合并的結(jié)果的編碼是unicode編碼,。 2.合并unicode和gbk,,會(huì)報(bào)錯(cuò):
'utf8' codec can't decode byte 0xb2 in position 0: invalid start byte
所以我們可以推測(cè): 在python對(duì)兩個(gè)字符串進(jìn)行操作的時(shí)候,如果這兩個(gè)字符串有一個(gè)是unicode編碼,,有一個(gè)是非unicode編碼,,python會(huì)將非unicode編碼的字符串decode成unicode編碼,,再進(jìn)行字符串操作 例如合并字符串的操作可以寫成以下的function:
def merge_str(str1, str2): if isinstance(str1, unicode) and not isinstance(str2, unicode): str2 = str2.decode(sys.getdefaultencoding()) elif not isinstance(str1, unicode) and isinstance(str2, unicode): str1 = str1.decode(sys.getdefaultencoding()) return str1 + str2
PS:sys.getdefaultencoding()的初始值是ascii 所以,
codec can't encode(decode) characters 這個(gè)報(bào)錯(cuò)是encode或decode這兩個(gè)方法產(chǎn)生的,,而這個(gè)方法的參數(shù)是sys.getdefaultencoding(),。如果用ascii編碼對(duì)帶有中文的字符串進(jìn)行解碼,就會(huì)報(bào)錯(cuò),。所以修改系統(tǒng)的默認(rèn)編碼可以避免這個(gè)報(bào)錯(cuò),。 當(dāng)執(zhí)行str 操作時(shí),python會(huì)執(zhí)行unicode_test.encode(sys.getdefaultencoding()) ,,所以也會(huì)報(bào)錯(cuò),。
3.#合并utf-8和gbk的時(shí)候卻不會(huì)報(bào)錯(cuò),,python會(huì)直接把兩個(gè)字符串合并,,不會(huì)有decode或encode的操作,但是輸出的時(shí)候,,部分字符串會(huì)亂碼,。 demo4.py
# encoding=gbkimport sysreload(sys)sys.setdefaultencoding('utf-8')unicode_test = u'測(cè)試test'utf8_test = unicode_test.encode('utf-8')gbk_test = unicode_test.encode('gbk')merge = utf8_test + gbk_testprint type(merge)print repr(merge)print merge
這里文件的encoding是gbk,sys.getdefaultencoding()設(shè)置為utf-8,,結(jié)果是:
<type 'str'>'\xe6\xb5\x8b\xe8\xaf\x95test\xb2\xe2\xca\xd4test'測(cè)試test????test
即gbk的部分亂碼了,。所以輸出的時(shí)候會(huì)按照sys.getdefaultencoding()的編碼來(lái)解碼。
三,、怎么判斷一個(gè)字符串的編碼方式
- 沒有辦法準(zhǔn)確地判斷一個(gè)字符串的編碼方式,,例如gbk的“\aa”代表甲,utf-8的“\aa”代表乙,,如果給定“\aa”怎么判斷是哪種編碼,?它既可以是gbk也可以是utf-8
- 我們能做的是粗略地判斷一個(gè)字符串的編碼方式,因?yàn)樯厦娴睦绲那闆r是很少的,,更多的情況是gbk中的'\aa'代表甲,,utf-8中是亂碼,例如?,,這樣我們就能判斷'\aa'是gbk編碼,,因?yàn)槿绻胾tf-8編碼去解碼的結(jié)果是沒有意義的
- 而我們經(jīng)常遇到的編碼其實(shí)主要的就只有三種:utf-8,gbk,,unicode
`
- unicode一般是
\u 帶頭的,,然后后面跟四位數(shù)字或字符串,例如 \u6d4b\u8bd5 ,,一個(gè)\u 對(duì)應(yīng)一個(gè)漢字
- utf-8一般是
\x 帶頭的,,后面跟兩位字母或數(shù)字,例如\xe6\xb5\x8b\xe8\xaf\x95\xe5\x95\x8a ,,三個(gè)\x 代表一個(gè)漢字
- gbk一般是
\x 帶頭的,,后面跟兩位字母或數(shù)字,例如\xb2\xe2\xca\xd4\xb0\xa1 ,兩個(gè)個(gè)\x 代表一個(gè)漢字
|