目錄
前言
一、字符編碼方式的來龍去脈。
1.字符集的含義。
2.編碼方式演化過程
1.ASCII
2.GB2312、GBK
3.Unicode
4.UTF-8
二、Python的字符編碼及相關(guān)操作
1.window系統(tǒng)的字符編碼
2.Python的字符編碼
1.Python中str與bytes的區(qū)別和聯(lián)系
2.Python encode()方法【對str進(jìn)行編碼】
3.Python decode()方法【對bytes進(jìn)行解碼】
三.Pyhton中文亂碼產(chǎn)生原因及常見問題的解決方法
1.中文亂碼產(chǎn)生的原因
2.使用Requests獲得網(wǎng)站內(nèi)容后,發(fā)現(xiàn)中文顯示亂碼。
3.非法字符拋出異常。
4.讀寫文件的中文亂碼
總結(jié)
前言
Python的字符編碼問題特別是涉及到中文的顯示時,亂碼、報出錯誤一直是讓新手頭疼的事情??赡芡ㄟ^百度能搜索到解決方法,但是根據(jù)網(wǎng)上的方法即使解決了錯誤,也很可能不知道為什么這個方法能夠解決這個錯誤。下面我根據(jù)自己的學(xué)習(xí)體驗,對Python的字符編碼進(jìn)行一個淺顯的梳理,以期對新入門Python的朋友有所幫助,如有錯誤望不吝賜教。
一、字符編碼方式的來龍去脈。
1.字符集及字符編碼的含義。
要徹底解決字符編碼的問題就不能不去了解到底什么是字符集。計算機(jī)從本質(zhì)上來說只認(rèn)識二進(jìn)制中的0和1。計算機(jī)并不識字,它實際上是把文本看做是一串“圖片”,每張“圖片”對應(yīng)一個字符。計算機(jī)程序在顯示文本時,必須借助一個記錄這個文字“圖片”如何顯示的“圖片”集合,從中找到每一個字符對應(yīng)“圖片”的數(shù)據(jù),并依樣畫葫蘆地把這個字“畫”到屏幕上。這個“圖片”就被稱為“字?!?,而記錄字模顯示數(shù)據(jù)的集合就被稱為“字符集”。
為方便程序查找,每個字符的字模數(shù)據(jù)在字符集中必須是有序排列的,而且每個字符都會被分配一個獨一無二的ID,這個ID就是字符的編碼。而在計算機(jī)進(jìn)行字符數(shù)據(jù)處理時,總是用這個編碼代表它表示的那個字符。也就是字符編碼格式。
2.編碼方式演化過程
1.ASCII
美國人發(fā)明了計算機(jī),制定了一套叫ASCII編碼格式,用于表示26個英文字母大小寫.每個編碼一個字節(jié),每個字節(jié)8位二進(jìn)制位(今天的計算機(jī)大部分都已經(jīng)是64位了,也就是一個字節(jié)64位二進(jìn)制)。ASCII 碼使用指定的7 位或8 位二進(jìn)制數(shù)組合來表示128 或256 種可能的字符。這樣在大部分情況下,英文與二進(jìn)制的轉(zhuǎn)換就變得容易多了。
2.GB2312、GBK
但是對于中國人來說,8位的二進(jìn)制ASCII碼完全不夠表示幾千個漢字的需要,為了解決這個問題中國國家標(biāo)準(zhǔn)總局1980年發(fā)布《信息交換用漢字編碼字符集》提出了GB2312編碼,用于解決漢字處理的問題。1995年又頒布了《漢字編碼擴(kuò)展規(guī)范》(GBK)(GB2312是簡體漢字編碼規(guī)范,但GBK是大字符集,不僅包含了簡體中文,繁體中文還包括了日語、韓語等所有亞洲文字的雙字節(jié)字符。)。最新漢字編碼標(biāo)準(zhǔn)GB18030,其中已經(jīng)可以支持中日韓以及藏文、蒙文,維吾爾文等少數(shù)民族文字。這樣我們就解決了計算機(jī)處理漢字的問題了。
?
3.Unicode
日本人也推出了一套shift_JIS編碼,用于表示日本
韓國人也推出了一套Euc_kr編碼,用于表示韓文
…
全世界有上百種語言,每種語言都推出一套編碼,而且互不兼容的話,是非常麻煩的一件事,只能自己跟自己玩。
于是Unicode編碼應(yīng)運而生,Unicode把所有語言都統(tǒng)一到一套編碼里,實現(xiàn)了編碼大統(tǒng)一,各國之間的編解碼再也不會出現(xiàn)亂碼了.Unicode一般用兩個字節(jié)表示一個字符,極為生僻的字符會用到四個字節(jié)。Unicode又被稱為統(tǒng)一碼、萬國碼;它為每種語言中的每個字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺進(jìn)行文本轉(zhuǎn)換、處理的要求。
4.UTF-8
問題又來了,美國人說,我本來一個字節(jié)就夠用了,現(xiàn)在用Unicode編碼的話至少一個字符要用到兩個字節(jié),多出來的一個字節(jié)不是白白浪費內(nèi)存空間嘛,這確實是個問題。于是大家一商量又推出了一套叫做UTF-8的編碼格式。UTF-8編碼把一個Unicode字符根據(jù)不同的數(shù)字大小編碼成1-6個字節(jié),常用的英文字母被編碼成1個字節(jié),漢字通常是3個字節(jié),只有很生僻的字符才會被編碼成4-6個字節(jié)。如果你要傳輸?shù)奈谋景罅坑⑽淖址肬TF-8編碼就能節(jié)省空間:
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
從上面的表格還可以發(fā)現(xiàn),UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以,大量只支持ASCII編碼的歷史遺留軟件可以在UTF-8編碼下繼續(xù)工作。
二、Python的字符編碼及相關(guān)操作
了解了編碼格式的演化過程,下面就進(jìn)入編碼格式的具體工作方式:
1.window系統(tǒng)的字符編碼
Python的字符編碼與系統(tǒng)字符編碼息息相關(guān),在了解Python編碼前我們先看一下系統(tǒng)字符編碼相關(guān)的知識。
在計算機(jī)內(nèi)存中,統(tǒng)一使用Unicode編碼,當(dāng)需要保存到硬盤或者需要傳輸?shù)臅r候,就轉(zhuǎn)換為UTF-8編碼。
用記事本編輯的時候,從文件讀取的UTF-8字符被轉(zhuǎn)換為Unicode字符到內(nèi)存里,編輯完成后,保存的時候再把Unicode轉(zhuǎn)換為UTF-8保存到文件:
瀏覽網(wǎng)頁的時候,服務(wù)器會把動態(tài)生成的Unicode內(nèi)容轉(zhuǎn)換為UTF-8再傳輸?shù)綖g覽器:
所以你看到很多網(wǎng)頁的源碼上會有類似<meta charset="UTF-8" />
的信息,表示該網(wǎng)頁正是用的UTF-8編碼。
2.Python的字符編碼
在Python 3版本中,字符串類型是str是以Unicode編碼的,也就是說Python的字符串支持多語言,在內(nèi)存中以Unicode表示,一個字符對應(yīng)若干個字節(jié)。如果要在網(wǎng)絡(luò)上傳輸,或者保存到磁盤上,就需要把str變?yōu)橐宰止?jié)為單位的bytes。在操作字符串時,我們經(jīng)常遇到str和bytes的互相轉(zhuǎn)換,為了避免亂碼問題,應(yīng)當(dāng)始終堅持使用UTF-8編碼對str和bytes進(jìn)行轉(zhuǎn)換。我們可以通過decode和encode方法對str和bytes進(jìn)行轉(zhuǎn)換,具體如下。
?
?下面具體分析一下在Python中,str與bytes的區(qū)別和轉(zhuǎn)換。
1.Python中str與bytes的區(qū)別和聯(lián)系
str主要在程序運行過程中使用運行于內(nèi)存,unicode編碼。bytes主要用于存儲和網(wǎng)絡(luò)傳輸。
字符串類型是str是以Unicode編碼的。
str='字符編碼' #與str=u'字符編碼'等效,只是省略了u. str為字符串是Unicode編碼
print(str)
print(type(str)) #類型為 str
'''
輸出:
字符編碼
<class 'str'>
'''
在網(wǎng)絡(luò)上傳輸,或者保存到磁盤上,就需要把str變?yōu)橐宰止?jié)為單位的bytes。bytes類型,通過ASCII編碼,如果字節(jié)存在中文會報錯
bytes=b'coding'
print(bytes)
print(type(bytes))
'''
輸出:
b'coding'
<class 'bytes'>
'''
bytes_error=b'中文' #bytes為 bytes類型,通過ASCII編碼,如果字節(jié)存在中文會報錯??!
'''
輸出:
SyntaxError: bytes can only contain ASCII literal characters.
'''
為解決這個問題,可以用通過字符串過渡,也就是先將中文存于字符串(Unicode編碼),再通過encode方法選擇合適編碼方式進(jìn)行編碼,具體如下所示? ?
str='中文ch'
bytes_ch=str.encode('utf-8')
print(bytes_ch)
print(type(bytes_ch))
'''
輸出:
b'\xe4\xb8\xad\xe6\x96\x87ch' #一個中文由3個字節(jié)表示,無法用ASCII碼輸出,就輸出16進(jìn)制表示
<class 'bytes'>
'''
在操作字符串時,我們經(jīng)常遇到str和bytes的互相轉(zhuǎn)換,通過deconde和encode進(jìn)行str與bytes的轉(zhuǎn)換,前提是使用同樣的編碼,否則就會產(chǎn)生亂碼問題,具體我們后面會進(jìn)行分析,為了避免亂碼問題,應(yīng)當(dāng)始終堅持使用UTF-8編碼對str和bytes進(jìn)行轉(zhuǎn)換。下面我們對encode和decode進(jìn)行詳細(xì)講解:?
2.Python encode()方法【對str進(jìn)行編碼】
encode()
方法為字符串類型(str
)提供的方法,用于將 str 類型轉(zhuǎn)換成 bytes 類型,這個過程也稱為“編碼”。encode() 方法的語法格式如下:
1 |
|
參數(shù) | 含義 |
---|---|
str | 表示要進(jìn)行轉(zhuǎn)換的字符串。 |
encoding = "utf-8" | 指定進(jìn)行編碼時采用的字符編碼,該選項默認(rèn)采用 utf-8 編碼。例如,如果想使用簡體中文,可以設(shè)置 gb2312。 當(dāng)方法中只使用這一個參數(shù)時,可以省略前邊的“encoding=”,直接寫編碼格式,例如 str.encode("UTF-8")。 |
errors = "strict" | 指定錯誤處理方式,其可選擇值可以是:
|
注意:使用 encode() 方法對原字符串進(jìn)行編碼,不會直接修改原字符串,如果想修改原字符串,需要重新賦值。
將 str 類型字符串“編碼方式”轉(zhuǎn)換成 bytes 類型。
1 2 3 |
|
此方式默認(rèn)采用 UTF-8 編碼,也可以手動指定其它編碼格式,例如:
1 2 3 |
|
3.Python decode()方法【對bytes進(jìn)行解碼】
和?encode()
方法正好相反,decode()
方法用于將?bytes
類型的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為 str 類型,這個過程也稱為“解碼”。
decode() 方法的語法格式如下:
1 |
|
參數(shù) | 含義 |
---|---|
bytes | 表示要進(jìn)行轉(zhuǎn)換的二進(jìn)制數(shù)據(jù)。 |
encoding="utf-8" | 指定解碼時采用的字符編碼,默認(rèn)采用 utf-8 格式。當(dāng)方法中只使用這一個參數(shù)時,可以省略“encoding=”,直接寫編碼方式即可。 注意,對 bytes 類型數(shù)據(jù)解碼,要選擇和當(dāng)初編碼時一樣的格式。 |
errors = "strict" | 指定錯誤處理方式,其可選擇值可以是:
|
將bytes類型字符串“編碼方式”轉(zhuǎn)換成str類型。
1 2 3 4 |
|
注意:如果編碼時采用的不是默認(rèn)的 UTF-8 編碼,則解碼時要選擇和編碼時一樣的格式,否則會拋出異常,例如:
1 2 3 4 5 6 7 8 9 |
|
三.Pyhton中文亂碼產(chǎn)生原因及常見問題的解決方法
1.中文亂碼產(chǎn)生的原因
中文亂碼問題個根本原因就是幾種常見中文編碼之間存在兼容性,一圖勝千言
所謂兼容性可以簡單理解為子集,同時存在也不沖突。圖中我們可以看出,ASCII被所有編碼兼容,而最常見的UTF8與GBK之間除了ASCII部分之外沒有交集,這也是平時業(yè)務(wù)中最常見的導(dǎo)致亂碼場景,使用UTF8去讀取GBK編碼的文字,可能會看到各種亂碼。由于在文件存儲和網(wǎng)絡(luò)傳輸中具體是使用哪種編碼并不明確,所以在讀取解碼時如果使用的解碼方式不對應(yīng),就會產(chǎn)生亂碼。
現(xiàn)將常見的幾種情況逐一進(jìn)行梳理,以供大家學(xué)習(xí)
2.使用Requests獲得網(wǎng)站內(nèi)容后,發(fā)現(xiàn)中文顯示亂碼。
例如:
import requests
from bs4 import BeautifulSoup
url='http://w3school.com.cn'
response=requests.get(url)
soup=BeautifulSoup(response.text,'lxml')
xx=soup.find('div',id='d1').h2.text
print(xx)
輸出
áì?èμ? Web ??ê??ì3ì - è?2??a·?
得到的結(jié)果是:áì?èμ? Web ??ê??ì3ì - è?2??a·?
這是因為代碼中獲得的網(wǎng)頁的響應(yīng)體response和網(wǎng)站的編碼方式不同,鍵入response.enconding得到的結(jié)果是ISO-8859-1。意思是Requests基于HTTP頭部推測的文本編碼方式是ISO-8859-1,實際網(wǎng)站真正使用的編碼是gb2312。我們只需要聲明response的正確編碼方式為gb2312就可以了。
response.encoding='gb2312'。
(如果還不能解決,有可能是網(wǎng)頁數(shù)據(jù)進(jìn)行了壓縮,可以使用response.content替換response.text。content會自動解碼gzip和defate傳輸編碼的響應(yīng)數(shù)據(jù),具體可以再去百度學(xué)習(xí))
3.非法字符拋出異常。
當(dāng)我們將某個字符串從GBK解碼為Unicode的時候(也可能是用其他編碼方式,比如'UTF-8'),可以采用上面介紹的decode方法,具體如下:
str.decode('GBK')
但實際可能會遇到如下異常
UnicodeDecodeError: 'gbk' codec can't decode bytes in position 7-8: illegal multibyte sequence
出錯原因是,字符串內(nèi)混入了多種編碼,于是出現(xiàn)了非法字符,如標(biāo)點符號全角半角、全角空格的不同編碼實現(xiàn)方式存儲等,只要出現(xiàn)一個非法字符就會報錯。解決方法很簡單就是采用ignore忽略,具體可以參照上面對decode函數(shù)的詳細(xì)介紹。
str.decode('GBK','ignore')
4.讀寫文件的中文亂碼
在使用Python3讀取和保存文件時一定要注明編碼方式。
同時在操作系統(tǒng)中保存的文件也應(yīng)該明確系統(tǒng)存儲時的編碼方式,具體可以參照前面對系統(tǒng)編碼方式的介紹,如記事本默認(rèn)的編碼方式時ANSI編碼(gbk),讀取時就應(yīng)該使用gbk進(jìn)行decode
另外,jison的保存中,如果希望能在記事本中讀取中文文本,可以設(shè)置參數(shù),ensure_ascii=false文章來源:http://www.zghlxwxcb.cn/news/detail-799237.html
import json
str='中文CH'
with open('ch.json','w',encoding='UTF-8') as f:
json.dump([str],f,ensure_ascii=False)
總結(jié)
以上內(nèi)容僅僅是個人學(xué)習(xí)中的一點體會,內(nèi)容多為網(wǎng)絡(luò)摘選,如有侵權(quán)可聯(lián)系我處理,不對之處望不吝賜教。文章來源地址http://www.zghlxwxcb.cn/news/detail-799237.html
到了這里,關(guān)于一篇文章徹底搞懂Python字符編碼方式(中文編碼,UTF-8,unicode,gb,gbk,中文亂碼,爬蟲中文亂碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!