詳解Python中的編碼問(wèn)題(encoding與decode、str與bytes)
1 引言
在文件讀寫(xiě)及字符操作時(shí),我們經(jīng)常會(huì)出現(xiàn)下面這幾種錯(cuò)誤:
- TypeError: write() argument must be str, not bytes
- AttributeError: 'URLError' object has no attribute 'code'
- UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' inposition 5747: illegal multibyte sequence
這些錯(cuò)誤一看就是編碼問(wèn)題, 本篇博文總結(jié)一下Python3文件讀寫(xiě)及字符操作中的編碼。
2 編碼發(fā)展史
?。?)ASCII編碼
眾所周知,計(jì)算機(jī)只能處理0和1,任何符號(hào)都轉(zhuǎn)換為0和1的序列才能處理。計(jì)算機(jī)中8個(gè)位(bit)作為一個(gè)字節(jié),所以1個(gè)字節(jié)能產(chǎn)生2的8次方個(gè)0和1的不同組合,也就是說(shuō)1個(gè)字節(jié)做多能表示256種字符。ASCII編碼就是用1個(gè)字節(jié)來(lái)存儲(chǔ)字符,計(jì)算機(jī)最初是美國(guó)人發(fā)明的,他們的符號(hào)不多,所以還將8個(gè)0和1序列中的第一位固定為0,ASCII只能表示127個(gè)字符。
?。?)GB2312編碼
美國(guó)佬的符號(hào)不多,所以ASCII編碼夠用,但是其他國(guó)家就不行了,每個(gè)國(guó)家符號(hào)數(shù)量都不一樣,就各自指定了自己的編碼。例如我們中國(guó)就制定了GB2312編碼。GB2312編碼用2個(gè)字節(jié)表示一個(gè)字符。
(3)Unicode編碼
每個(gè)國(guó)家都用自己的編碼,編碼一朵就容易亂套,也沒(méi)法交流,所以需要一種編碼把各個(gè)國(guó)家的編碼都囊括進(jìn)去,這就是Unicode編碼的由來(lái)。所以,Unicode也被稱為萬(wàn)國(guó)碼。Unicode編碼也用2個(gè)字節(jié)存儲(chǔ)一個(gè)字符。
?。?)utf-8編碼
Unicode編碼解決了編碼不能通用的問(wèn)題,但是卻容易浪費(fèi)內(nèi)存,尤其是在存儲(chǔ)英文的時(shí)候,例如一個(gè)字符“A”,ASCII編碼只需要1個(gè)字節(jié)就夠,但是Unicode編碼必須要用2個(gè)字節(jié)。為了解決這一問(wèn)題,就有了utf-8編碼。 utf-8編碼把存儲(chǔ)英文依舊用一個(gè)字節(jié),漢字就3個(gè)字節(jié)。特別是生僻的編程4-6字節(jié),如果傳輸大量英文,utf-8作用就很明顯了。
utf-8編碼進(jìn)行存儲(chǔ)時(shí)有極大地優(yōu)勢(shì),但是當(dāng)讀取到計(jì)算機(jī)內(nèi)存時(shí)卻不大合適,因?yàn)閡tf-8編碼是變長(zhǎng)的,不方便尋址和索引,所以在計(jì)算機(jī)內(nèi)存中,還是轉(zhuǎn)化為Unicode編碼合適些。這就可以解釋為什么每次讀取文本時(shí),要將編碼轉(zhuǎn)化為Unicode編碼,而將內(nèi)存中的字符寫(xiě)入文件存儲(chǔ)時(shí),要將編碼轉(zhuǎn)化為utf-8了。
3 str與bytes
在Python3中,文本總是為Unicode編碼,在類型上為str類,也就是說(shuō)Python編譯器只會(huì)把Unicode編碼下的二進(jìn)制流顯示為我們可識(shí)別的符號(hào)。二進(jìn)制流在Python中也有一個(gè)專門的類用于表示這種二進(jìn)制序列,那就是bytes(在Python中這個(gè)二進(jìn)制序列顯示為16進(jìn)制,但本質(zhì)還是二進(jìn)制)。一個(gè)str在不同的編碼下就可以轉(zhuǎn)化為不同的bytes(二進(jìn)制流),反之,要將bytes轉(zhuǎn)化為可識(shí)別的str就必須用對(duì)應(yīng)的編碼,否則就會(huì)報(bào)錯(cuò)。
用人類語(yǔ)言類比一下:我們要表達(dá)“吃飯”這件事物(str),翻譯為各個(gè)國(guó)家的文字后有各不相同的表示,中文表示為“吃飯”,英文表示為“eat”,這就是“吃飯”這個(gè)str在不同編碼寫(xiě)的表示。但官方只認(rèn)中文(Pythonstr只認(rèn)Unicode編碼),所以就必須把“eat”用英語(yǔ)(編碼)的表示方式轉(zhuǎn)化為中文的“吃飯”(Unicode編碼),官方才會(huì)顯示知道是吃飯這件事。
>>> s = '吃飯' >>> type(s) <class 'str'> >>> s1 = s.encode(encoding='utf-8') >>> type(s1) <class 'bytes'> >>> s1 b'\xe5\x90\x83\xe9\xa5\xad' >>> s2 = s.encode(encoding='gb2312') >>> type(s2) <class 'bytes'> >>> s2 b'\xb3\xd4\xb7\xb9' >>> s1.decode('utf-8') '吃飯' >>> s2.decode('gb2312') '吃飯'
4 文件編碼
在python 3 中字符是以Unicode的形式存儲(chǔ)的,當(dāng)然這里所說(shuō)的存儲(chǔ)是指存儲(chǔ)在計(jì)算機(jī)內(nèi)存當(dāng)中,如果是存儲(chǔ)在硬盤(pán)里,Python 3的字符是以bytes形式存儲(chǔ),也就是說(shuō)如果要將字符寫(xiě)入硬盤(pán),就必須對(duì)字符進(jìn)行encode。對(duì)上面這段話再解釋一下,如果要將str寫(xiě)入文件,如果以‘w'模式寫(xiě)入,則要求寫(xiě)入的內(nèi)容必須是str類型;如果以‘wb'形式寫(xiě)入,則要求寫(xiě)入的內(nèi)容必須是bytes類型。文章開(kāi)頭出現(xiàn)的幾種錯(cuò)誤,就是因?yàn)閷?xiě)入模式與寫(xiě)入內(nèi)容的數(shù)據(jù)類型不匹配造成的。
s1 = '你好' #如果是以‘w'的方式寫(xiě)入,寫(xiě)入前一定要進(jìn)行encoding,否則會(huì)報(bào)錯(cuò) with open('F:\\1.txt','w',encoding='utf-8') as f1: f1.write(s1) s2 = s1.encode("utf-8")#轉(zhuǎn)換為bytes的形式 #這時(shí)候?qū)懭敕绞揭欢ㄒ恰畐b',且一定不能加encoding參數(shù) with open('F:\\2.txt','wb') as f2: f2.write(s2)
有的人會(huì)問(wèn),我在系統(tǒng)里面用文本編輯器打開(kāi)以bytes形式寫(xiě)入的2.txt文件,發(fā)現(xiàn)里面顯示的是‘你好',而不是‘b'\xe4\xbd\xa0\xe5\xa5\xbd'',因?yàn)槲谋疚臋n打開(kāi)2.txt時(shí),系統(tǒng)會(huì)用合適的編碼將其顯示為對(duì)應(yīng)的符號(hào),然后才給你看到。
5 網(wǎng)頁(yè)編碼
網(wǎng)頁(yè)編碼和文件編碼方法差不多,如下urlopen下載下來(lái)的網(wǎng)頁(yè)read()且用decoding(‘utf-8')解碼,那就必須以‘w'的方式寫(xiě)入文件。如果只是read()而不用encoding(‘utf-8')進(jìn)行編碼,一定要以‘wb'方式寫(xiě)入:
以‘w'方式寫(xiě)入時(shí):
response= url_open('http://blog.csdn.net/gs_zhaoyang/article/details/13768925 ' ,timeout=5 )#自定義的一個(gè)網(wǎng)頁(yè)下載函數(shù) #此處以UTF-8方式進(jìn)行解碼,解碼后的數(shù)據(jù)以u(píng)nicode的方式存儲(chǔ)在html中 html = response.read().decode('UTF-8') print(type(html))#輸出結(jié)果:<class 'str'> #這時(shí)寫(xiě)入方式一定要加encoding,以encoding # 即UTF-8的方式對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行編碼才能寫(xiě)入 with open('F:\DownloadAppData\html.txt',"w" , encoding='UTF-8') as f: f.write(html)
以‘wb'方式寫(xiě)入:
response= url_open('http://blog.csdn.net/gs_zhaoyang/article/details/13768925 ' ,timeout=5 ) html = response.read()#此處不需要進(jìn)行解碼,下載下來(lái) print(type(html))#輸出結(jié)果:<class 'bytes'> with open('F:\DownloadAppData\html.txt',"wb" ) as f: f.write(html)
如果要在Python3中,對(duì)urlopen下載下來(lái)的網(wǎng)頁(yè)進(jìn)行字符操作(例如正則匹配、lxml提取),就必須decode成Unicode。
作者:奧辰
微信號(hào):chb1137796095
Github:https://github.com/ChenHuabin321
歡迎加V交流,共同學(xué)習(xí),共同進(jìn)步!
以上就是詳解Python中的編碼問(wèn)題(encoding與decode、str與bytes)的詳細(xì)內(nèi)容,更多關(guān)于python 編碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
calendar在python3時(shí)間中常用函數(shù)舉例詳解
這篇文章主要介紹了calendar在python3時(shí)間中常用函數(shù)的相關(guān)文章,對(duì)此知識(shí)點(diǎn)有興趣的朋友們可以學(xué)習(xí)下。2020-11-11python實(shí)現(xiàn)健康碼查驗(yàn)系統(tǒng)
這篇文章主要介紹了?python實(shí)現(xiàn)健康碼查驗(yàn)系統(tǒng),主要用到的是python用了opencv庫(kù)和pyzbar庫(kù),文中給大家提供一段代碼判斷是否綠碼,需要的朋友可以參考下2022-04-04Python實(shí)現(xiàn)帶百分比的進(jìn)度條
本文給大家匯總介紹了3種使用Python實(shí)現(xiàn)帶百分比進(jìn)度條的代碼,非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下2016-06-06Python解決多進(jìn)程間訪問(wèn)效率低的方法總結(jié)
這篇文章主要為大家詳細(xì)介紹了當(dāng)Python多進(jìn)程間訪問(wèn)效率低時(shí),應(yīng)該如何解決?文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-09-09python開(kāi)發(fā)游戲的前期準(zhǔn)備
在本篇文章中我們給大家分享了關(guān)于python開(kāi)發(fā)游戲的前期準(zhǔn)備以及用到的工具等內(nèi)容,需要的朋友們跟著參考下。2019-05-05基于pdf2docx模塊Python實(shí)現(xiàn)批量將PDF轉(zhuǎn)Word文檔的完整代碼教程
這篇文章主要介紹了基于pdf2docx模塊Python實(shí)現(xiàn)批量將PDF轉(zhuǎn)Word文檔的完整代碼教程,PDF文件是一種常見(jiàn)的文檔格式,如何轉(zhuǎn)換成word呢,需要的朋友可以參考下2023-04-04