一、python程序編輯界面和運(yùn)行界面通常都是默認(rèn)unicode編碼字符串的,編輯界面則是ascii編碼的,也就是程序語(yǔ)句是用ascii編碼的。但最困擾編程小白的不在這里,請(qǐng)看二、
二、python的文本可以通過(guò)encode轉(zhuǎn)化為字節(jié)流bytes,這時(shí)候困擾編程小白的問(wèn)題來(lái)了。
(1)encode轉(zhuǎn)化后的字節(jié)流bytes是不是字符串?
答:bytes不是字符串str。在python中,bytes是字節(jié)流bytes對(duì)象,字符串是字符串str對(duì)象。
(2)bytes不是字符串,那b'abc'怎么跟'abc'那么像?
答:這就不得不提一下坑爹的程序語(yǔ)言編寫(xiě)者們了,或者說(shuō)console界面編寫(xiě)者們了。注意:在運(yùn)行界面輸出bytes時(shí)候,它是采取這樣的原則的:每讀一個(gè)字節(jié)就和ascii碼比對(duì)一下,如果符合ascii碼的可顯示字符(特殊字符,字母和數(shù)字,控制字符除外),那這個(gè)字節(jié)就按照ascii碼來(lái)表示,否則就按十六進(jìn)制\x某某來(lái)表示。
>>> b'\x40\x41'
b'@A'
>>> b'\x00\x01'
b'\x00\x01'
這坑爹的原則不知道坑了多少迷糊的小白:怎么一會(huì)顯示一個(gè)\xff,怎么一會(huì)又顯示出一個(gè)a,而且看起來(lái)又是和字符串沒(méi)啥區(qū)別,搞暈了。bytes對(duì)象的顯示原則是這樣,所以bytes對(duì)象不能包含超過(guò)0到127內(nèi)ascii碼范圍的unicode字符串,而不能接受超過(guò)這個(gè)范圍的unicode字符串。
>>> b'中'。
File "", line 1
SyntaxError: bytes can only contain ASCII literal characters.
(3)好啦,那在編輯界面怎么輸入bytes?
答:直接用b'字符串'表示bytes對(duì)象,這時(shí)候相當(dāng)于一個(gè)接受0到127內(nèi)ascii碼范圍內(nèi)的unicode碼字符串的函數(shù)bytes(‘字符串’)。
>>> b'@&*hello'
b'@&*hello'
(4)好,如果我不用字符串表示bytes呢?又怎么搞?
答:直接用\x加兩位十六進(jìn)制數(shù)字表示一個(gè)字節(jié)就可以了。
>>> b'\x41\xff\x2e\97'
b'A\xff.\\97'
(5)字符串可以通過(guò)encode轉(zhuǎn)化為bytes,bytes可以通過(guò)decode轉(zhuǎn)化為字符串,問(wèn)題又來(lái)了,不是學(xué)挖掘機(jī)哪家強(qiáng),而是一個(gè)字符a有很多種編碼的,按哪一種轉(zhuǎn)化為bytes?bytes本身就是一串0和1的數(shù)字,按不同方式讀可以解釋成不同的字符,又怎么搞?
答:encode(‘編碼方式’)時(shí)指定按那個(gè)編碼轉(zhuǎn)化為bytes。反之,decode(‘編碼方式’)指定按那種方式讀取字節(jié)碼(0和1構(gòu)成的數(shù)字流)。
>>> 'a'.encode('ascii')
b'a'
>>> 'a'.encode('utf-8')
b'a'
>>> 'a'.encode('gbk')
b'a'
>>> '中'.encode('gbk')
b'\xd6\xd0'
>>> '中'.encode('utf-8')
b'\xe4\xb8\xad'
(6)坑爹的問(wèn)題又來(lái)了,python程序編輯界面的unicode碼u'a'是字符串還是字節(jié)碼?unicode碼又怎么表示?
答:u'a'不是字節(jié)碼,是字符串!坑爹??!換句話(huà)說(shuō)u'a'和'a'是一樣一樣的!坑爹?。?/p>
>>> type(u'a')
<class 'str'>
unicode碼再python里有兩種表示方式:
u'字符串'或者'\u四位十六進(jìn)制數(shù)'。它們是等價(jià)的,而且都是str對(duì)象。注意,'\\u四位十六進(jìn)制數(shù)'與'\u四位十六進(jìn)制數(shù)'并不相等,'\\u四位十六進(jìn)制數(shù)'='\\’(斜杠本身是轉(zhuǎn)義字符要經(jīng)過(guò)轉(zhuǎn)義表示)+'u四位十六進(jìn)制數(shù)'。
>>> print('\u0065')
e
>>> print('\\u0065')
\u0065
(7)那如果它是字符串,我要轉(zhuǎn)化為unicode碼咋整?用encode指定unicode方式?
答:如果需要將內(nèi)存用的unicode碼直接保存,就指定編碼方式是'unicode-escape'!
>>> '中'.encode('unicode')
Traceback (most recent call last): ?File "", line 1, inLookupError: unknown encoding: unicode
>>> '中'.encode('unicode-escape')
b'\\u4e2d'
好!如果我不指定編碼方式呢,又會(huì)怎么樣?
encode默認(rèn)編碼方式是?。?!utf-8!
>>> '中'.encode()
b'\xe4\xb8\xad'
三、python的py文件里指定編碼方式,是指指定文件里所有內(nèi)容都是按編碼方式編碼還是字符串按編碼方式編碼?
答:py文件的編碼方式是ascii碼,字符串默認(rèn)編碼是unicode碼,指定編碼方式是指定從硬盤(pán)讀取py文件的編碼方式。
實(shí)際上,要區(qū)分以下編碼:系統(tǒng)默認(rèn)編碼(cmd,widows的txt文件),編輯界面編碼(編輯界面顯示文本的編碼),運(yùn)行界面編碼(運(yùn)行界面顯示文本的編碼),代碼文件(py文件)編碼,讀入的文本編碼,寫(xiě)出的文本編碼。
(1)系統(tǒng)默認(rèn)編碼
以windows簡(jiǎn)體中文為例,系統(tǒng)默認(rèn)編碼是gbk,命令行輸入chcp查看活動(dòng)頁(yè)代碼為936。
如果將超出gbk范圍的unicode碼,寫(xiě)入系統(tǒng)的txt文件,報(bào)錯(cuò)!在cmd中print,報(bào)錯(cuò)!
處理方式:將unicode碼encode為bytes再寫(xiě)入或print。
(2)編輯界面編碼
編輯界面編碼默認(rèn)是ascii碼,也就是寫(xiě)的程序語(yǔ)句默認(rèn)是ascii編碼,但一旦涉及到ascii碼不能表示的,就隱形轉(zhuǎn)換為系統(tǒng)默認(rèn)編碼表示,程序語(yǔ)句中的字符串默認(rèn)是unicode碼,也就是內(nèi)存中的編碼。
在py文件頭聲明文件的編碼方式:
#-*- coding:utf-8 -*-
對(duì)編輯界面的字符串沒(méi)有什么實(shí)質(zhì)上的影響的!
pycharm編輯界面是默認(rèn)utf-8的。所以有時(shí)在pycharm中編輯的代碼中沒(méi)有問(wèn)題的字符串,放到cmd中編輯就會(huì)出現(xiàn)問(wèn)題。設(shè)置在Editor->Code Style->File Ecoding->Project Ecoding。
(3)運(yùn)行界面編碼
cmd中運(yùn)行程序,默認(rèn)顯示文本的編碼是ascii碼,一旦超出范圍就隱式轉(zhuǎn)換為系統(tǒng)編碼。
在py文件頭聲明文件的編碼方式:
#-*- coding:utf-8 -*-
對(duì)編輯界面和運(yùn)行界面的字符串也沒(méi)有什么實(shí)質(zhì)上的影響的!坑爹啊!指定編碼方式是告訴系統(tǒng)按照什么編碼來(lái)讀這個(gè)py文件的。
pycharm運(yùn)行界面是默認(rèn)utf-8的。所以有時(shí)在pycharm中沒(méi)有問(wèn)題的字符串,放到cmd中就會(huì)出現(xiàn)問(wèn)題。所以有時(shí)在pycharm中print沒(méi)有問(wèn)題的字符串,放到cmd中print就會(huì)出現(xiàn)問(wèn)題。設(shè)置在Editor->Code Style->File Ecoding->IDE Ecoding。
(4)代碼文件編碼
代碼文件(py文件)本身也是一個(gè)文本,它也需要在硬盤(pán)或者其他載體上保存,默認(rèn)編碼是系統(tǒng)編碼。這樣的話(huà),一旦py文件copy到不同平臺(tái),問(wèn)題就會(huì)發(fā)生,出現(xiàn)亂碼。
特別注意:
在py文件頭聲明文件的編碼方式:
#-*- coding:utf-8 -*-
只是告訴python編譯器在讀取代碼文件時(shí)按utf-8方式讀取,但這個(gè)聲明不能將py文件保存成utf-8格式的!
處理方式:
py文件要多平臺(tái)運(yùn)行,最好統(tǒng)一采用一個(gè)編碼方式(如‘utf-8’)編輯和保存。
(5)讀入文件編碼
當(dāng)從網(wǎng)絡(luò)或者硬盤(pán)讀入文件的時(shí)候,實(shí)質(zhì)上讀到的是字節(jié)流:
硬盤(pán)讀入文件的默認(rèn)編碼方式是系統(tǒng)編碼方式,當(dāng)出現(xiàn)超過(guò)gbk范圍的字節(jié)出現(xiàn),報(bào)錯(cuò)!
網(wǎng)絡(luò)讀入文件時(shí),因?yàn)樽x入的是字節(jié),不會(huì)報(bào)錯(cuò),但一旦要print時(shí)就會(huì)報(bào)錯(cuò)!
所以,如果不能按照讀入文本的編碼方式轉(zhuǎn)化為unicode,就會(huì)出現(xiàn)問(wèn)題。
處理方式:
因?yàn)閞ead()沒(méi)有編碼方式參數(shù),只能讀入bytes然后在解碼為unicode碼或者其他編碼。
判斷讀入內(nèi)容的編碼方式可以用chardet的detect方法,接受一段bytes參數(shù),返回一個(gè)結(jié)果的字典,里面包含編碼方式和信度區(qū)間。
withopen('/Users/liaorikun/Desktop/gbktest.txt','rb')asf:
s = f.read()
chatest = chardet.detect(s)
# print(s)
print(chatest)
檢測(cè)結(jié)果:
{'encoding': 'GB2312', 'confidence': 0.99}
(6)寫(xiě)出文件編碼
寫(xiě)文件編碼參看(1)
如果想將文本直接以u(píng)nicode碼保存到文件,用encode(‘unicode-escape’)轉(zhuǎn)化為bytes,寫(xiě)入文件。
如果想將文本以u(píng)tf-8形式保存到文件,用encode(‘utf-8’)轉(zhuǎn)化為utf-8編碼的bytes,寫(xiě)入文件。