一航缀、python程序編輯界面和運(yùn)行界面通常都是默認(rèn)unicode編碼字符串的艰山,編輯界面則是ascii編碼的涣仿,也就是程序語(yǔ)句是用ascii編碼的。但最困擾編程小白的不在這里砸琅,請(qǐng)看二宋距、
二、python的文本可以通過encode轉(zhuǎn)化為字節(jié)流bytes症脂,這時(shí)候困擾編程小白的問題來了谚赎。
(1)encode轉(zhuǎn)化后的字節(jié)流bytes是不是字符串?
答:bytes不是字符串str诱篷。在python中壶唤,bytes是字節(jié)流bytes對(duì)象,字符串是字符串str對(duì)象棕所。
(2)bytes不是字符串闸盔,那b'abc'怎么跟'abc'那么像?
答:這就不得不提一下坑爹的程序語(yǔ)言編寫者們了琳省,或者說console界面編寫者們了迎吵。注意:在運(yùn)行界面輸出bytes時(shí)候,它是采取這樣的原則的:每讀一個(gè)字節(jié)就和ascii碼比對(duì)一下针贬,如果符合ascii碼的可顯示字符(特殊字符击费,字母和數(shù)字,控制字符除外)桦他,那這個(gè)字節(jié)就按照ascii碼來表示蔫巩,否則就按十六進(jìn)制\x某某來表示。
>>> b'\x40\x41'
b'@A'
>>> b'\x00\x01'
b'\x00\x01'
這坑爹的原則不知道坑了多少迷糊的小白:怎么一會(huì)顯示一個(gè)\xff,怎么一會(huì)又顯示出一個(gè)a快压,而且看起來又是和字符串沒啥區(qū)別圆仔,搞暈了。bytes對(duì)象的顯示原則是這樣蔫劣,所以bytes對(duì)象不能包含超過0到127內(nèi)ascii碼范圍的unicode字符串坪郭,而不能接受超過這個(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)字符串可以通過encode轉(zhuǎn)化為bytes外驱,bytes可以通過decode轉(zhuǎn)化為字符串育灸,問題又來了,不是學(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)坑爹的問題又來了犯助,python程序編輯界面的unicode碼u'a'是字符串還是字節(jié)碼癣漆?unicode碼又怎么表示?
答:u'a'不是字節(jié)碼剂买,是字符串惠爽!坑爹啊瞬哼!換句話說u'a'和'a'是一樣一樣的婚肆!坑爹啊倒槐!
>>> 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)過轉(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)編碼方式是!4嚷酢若贮!utf-8!
>>> '中'.encode()
b'\xe4\xb8\xad'
三痒留、python的py文件里指定編碼方式谴麦,是指指定文件里所有內(nèi)容都是按編碼方式編碼還是字符串按編碼方式編碼?
答:py文件的編碼方式是ascii碼伸头,字符串默認(rèn)編碼是unicode碼匾效,指定編碼方式是指定從硬盤讀取py文件的編碼方式。
實(shí)際上恤磷,要區(qū)分以下編碼:系統(tǒng)默認(rèn)編碼(cmd面哼,widows的txt文件),編輯界面編碼(編輯界面顯示文本的編碼)碗殷,運(yùn)行界面編碼(運(yùn)行界面顯示文本的編碼)精绎,代碼文件(py文件)編碼,讀入的文本編碼锌妻,寫出的文本編碼代乃。
(1)系統(tǒng)默認(rèn)編碼
以windows簡(jiǎn)體中文為例,系統(tǒng)默認(rèn)編碼是gbk仿粹,命令行輸入chcp查看活動(dòng)頁(yè)代碼為936搁吓。
如果將超出gbk范圍的unicode碼,寫入系統(tǒng)的txt文件吭历,報(bào)錯(cuò)堕仔!在cmd中print,報(bào)錯(cuò)晌区!
處理方式:將unicode碼encode為bytes再寫入或print摩骨。
(2)編輯界面編碼
編輯界面編碼默認(rèn)是ascii碼,也就是寫的程序語(yǔ)句默認(rèn)是ascii編碼朗若,但一旦涉及到ascii碼不能表示的恼五,就隱形轉(zhuǎn)換為系統(tǒng)默認(rèn)編碼表示,程序語(yǔ)句中的字符串默認(rèn)是unicode碼哭懈,也就是內(nèi)存中的編碼灾馒。
在py文件頭聲明文件的編碼方式:
#-*- coding:utf-8 -*-
對(duì)編輯界面的字符串沒有什么實(shí)質(zhì)上的影響的!
pycharm編輯界面是默認(rèn)utf-8的遣总。所以有時(shí)在pycharm中編輯的代碼中沒有問題的字符串睬罗,放到cmd中編輯就會(huì)出現(xià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)行界面的字符串也沒有什么實(shí)質(zhì)上的影響的花盐!坑爹拜锕印!指定編碼方式是告訴系統(tǒng)按照什么編碼來讀這個(gè)py文件的卒暂。
pycharm運(yùn)行界面是默認(rèn)utf-8的。所以有時(shí)在pycharm中沒有問題的字符串娄帖,放到cmd中就會(huì)出現(xiàn)問題也祠。所以有時(shí)在pycharm中print沒有問題的字符串,放到cmd中print就會(huì)出現(xiàn)問題近速。設(shè)置在Editor->Code Style->File Ecoding->IDE Ecoding诈嘿。
(4)代碼文件編碼
代碼文件(py文件)本身也是一個(gè)文本,它也需要在硬盤或者其他載體上保存削葱,默認(rèn)編碼是系統(tǒng)編碼奖亚。這樣的話,一旦py文件copy到不同平臺(tái)析砸,問題就會(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ò)或者硬盤讀入文件的時(shí)候夹攒,實(shí)質(zhì)上讀到的是字節(jié)流:
硬盤讀入文件的默認(rèn)編碼方式是系統(tǒng)編碼方式,當(dāng)出現(xiàn)超過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)問題。
處理方式:
因?yàn)閞ead()沒有編碼方式參數(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)寫出文件編碼
寫文件編碼參看(1)
如果想將文本直接以u(píng)nicode碼保存到文件,用encode(‘unicode-escape’)轉(zhuǎn)化為bytes置侍,寫入文件映之。
如果想將文本以u(píng)tf-8形式保存到文件,用encode(‘utf-8’)轉(zhuǎn)化為utf-8編碼的bytes蜡坊,寫入文件杠输。