亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

要說在整個(gè)編程領(lǐng)域中最難的問題有哪些的話,字符編碼的問題,也就是亂碼問題,絕對算得上很多程序員寫代碼時(shí)的一個(gè)“噩夢”。以至于在IT界有個(gè)著名的笑話,“手持一把錕斤拷,口中直呼燙燙燙”,如果你笑了,那么你肯定是做IT的,哈哈哈。而在Python這門語言中,因?yàn)閜ython2和python3本身編碼機(jī)制完全不一樣,所以這個(gè)問題又尤其突出。包括我本人在內(nèi),也被這個(gè)編碼問題困擾了很久,一直沒有完全搞明白。后來,為了徹底解決編碼問題,專門查詢了很多的書籍和資料,終于搞清楚了關(guān)于編碼問題的來龍去脈以及各種情況下存在的問題以及解決方式,今天這篇文章就來做一個(gè)總結(jié),相信大家只要認(rèn)真看了之后,媽媽再也不會(huì)擔(dān)心你的編碼問題了。

要徹底弄清楚亂碼是怎么來的,有兩個(gè)大的關(guān)鍵因素必須要了解:一個(gè)是究竟有哪些編碼類型,各種類型有哪些不同的特點(diǎn),這些必須爛熟于心。二是你的代碼運(yùn)行環(huán)境是什么。比如是在命令行運(yùn)行?還是在編輯器中運(yùn)行?在python2中還是在python3中?在linux系統(tǒng)里面?還是在windows系統(tǒng)里面?弄清楚這兩個(gè)問題,亂碼問題便會(huì)迎刃而解。接下來我們來一一解決這些問題。

一、編碼類型

很多人想不明白為什么計(jì)算機(jī)中有這么多亂七八糟各種各樣的編碼,比如什么ASCII啊,GBK,GB2312,UNICODE,UTF8,這些都是什么鬼?為什么要有這么多不同的編碼格式?要想搞清楚這些編碼問題,必須先了解一下關(guān)于字符編碼的歷史,這些都是祖上留下來的“孽債”。

1. 什么是字符編碼

首先我們來了解下究竟什么是字符編碼,為什么要有字符編碼這個(gè)東西出現(xiàn)?原因很簡單,計(jì)算機(jī)從本質(zhì)上來說只認(rèn)識(shí)二進(jìn)制中的0和1,可以說任何數(shù)據(jù)在計(jì)算機(jī)中實(shí)際的物理表現(xiàn)形式也就是0和1,如果你將硬盤拆開,你是看不到所謂的數(shù)字0和1的,你能看到的只是一塊光滑閃亮的磁盤,如果你用足夠大的放大鏡你就能看到磁盤的表面有著無數(shù)的凹凸不平的元件,凹下去的代表0,突出的代表1,我們用bit(位)來表示每個(gè)這種二進(jìn)制的數(shù),這就是計(jì)算機(jī)用來表現(xiàn)二進(jìn)制的方式。而我們在處理數(shù)據(jù)時(shí),一般并不是按位來進(jìn)行處理,而是按照字節(jié)(byte)來進(jìn)行處理的,一個(gè)字節(jié)byte=8bit。那現(xiàn)在我們面臨了第一個(gè)問題:如何讓人類語言能夠被計(jì)算機(jī)正確理解呢?我們以英文為例(因?yàn)橛?jì)算機(jī)是美國佬發(fā)明的,所以最開始當(dāng)然只考慮英文的情況),英文中有英文字母(大小寫)、標(biāo)點(diǎn)符號、特殊符號。如果我們將這些字母與符號給予固定的編號,然后將這些編號轉(zhuǎn)變?yōu)槎M(jìn)制用字節(jié)來表示,那么計(jì)算機(jī)明顯就能夠正確讀取這些符號,同時(shí)通過這些編號,計(jì)算機(jī)也能夠?qū)⒍M(jìn)制轉(zhuǎn)化為編號對應(yīng)的字符再顯示給人類去閱讀。所以,基于這種思想,便產(chǎn)生了ASCII碼。

2. ASCII編碼

ASCII碼是人類計(jì)算機(jī)歷史上最早發(fā)明的字符集,大家都知道 ,計(jì)算機(jī)是美國佬發(fā)明的,他們只用英文,所以可以說ASCII碼是專門為表示英文、數(shù)字以及英文標(biāo)點(diǎn)符號而生。由于英文本身比較簡單,就是由26個(gè)字母組成,加上0-9十個(gè)數(shù)字以及一些英文的標(biāo)點(diǎn)符號。而在計(jì)算機(jī)中,1byte=8bit,也就是說有從0000000-11111111共2的8次方共256種不同的組合,這些組合已經(jīng)足夠存儲(chǔ)所有的這些英文字母、數(shù)字以及標(biāo)點(diǎn)了,所以早期的編碼只有ASCII編碼。

3. GB2312以及其他編碼

如果全世界的人都使用英文的話,今天我們就不必這么費(fèi)神來研究編碼問題了。正因?yàn)槿澜绲恼Z言太多,大家都想使用自己熟悉的語言來使用計(jì)算機(jī),比如中國人用計(jì)算機(jī)當(dāng)然使用中文了。那么問題來了,在中文中光常用的漢字就已經(jīng)達(dá)到了6000多個(gè)了,很明顯之前的ASCII碼已經(jīng)完全無法滿足漢字存儲(chǔ)的需求了。怎么辦?既然使用ASCII碼這樣一個(gè)字節(jié)無法搞定,那么我們自然想到能不能多用1個(gè)字節(jié)是不能就能搞定了呢?所以,為了滿足國內(nèi)在計(jì)算機(jī)中使用漢字的需要,中國國家標(biāo)準(zhǔn)總局發(fā)布了一系列的漢字字符集國家標(biāo)準(zhǔn)編碼,統(tǒng)稱為GB碼,或國標(biāo)碼。其中最有影響的是于1980年發(fā)布的《信息交換用漢字編碼字符集 基本集》,標(biāo)準(zhǔn)號為GB 2312-1980,因其使用非常普遍,也常被通稱為國標(biāo)碼。GB2312編碼通行于我國內(nèi)地;新加坡等地也采用此編碼。幾乎所有的中文系統(tǒng)和國際化的軟件都支持GB 2312。所以,大家可以理解為,GB系列的編碼是為了適應(yīng)復(fù)雜的中文編碼而對ASCII碼的一種擴(kuò)充。

4. UNICODE標(biāo)準(zhǔn)編碼

既然咱們中國人能夠?qū)SCII碼進(jìn)行擴(kuò)充,以便于顯示更復(fù)雜的中文,那么其他國家呢?比如日本、韓國,其實(shí)也面臨著同樣的問題。所以,他們自然也會(huì)對ASCII碼擴(kuò)展出自己的一套編碼。假設(shè)每種語言都自己搞一套,工作量上去了不說,還為不同編碼之間的轉(zhuǎn)換和顯示造成了巨大的困難,這也行不通啊。所以,為了簡化不同編碼之間的顯示和轉(zhuǎn)換問題,很有必要搞一套統(tǒng)一的編碼格式出來?;谶@種情況一種新的編碼誕生了:Unicode。Unicode又被稱為統(tǒng)一碼、萬國碼;它為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求。Unicode支持歐洲、非洲、中東、亞洲(包括統(tǒng)一標(biāo)準(zhǔn)的東亞象形漢字和韓國表音文字)。這樣不管你使用的是英文或者中文,日語或者韓語,在Unicode編碼中都有收錄,且對應(yīng)唯一的二進(jìn)制編碼。這樣大家都開心了,只要大家都用Unicode編碼,那就不存在這些轉(zhuǎn)碼的問題了,什么樣的字符都能夠解析了。

5. UTF-8編碼

看完上面的UNICODE編碼,大家是不是想編碼問題已經(jīng)解決了呢?既然UNICODE能夠兼容所有已知的語言和文字,那就全部按照UNICODE來編碼就行了唄。如果你這樣想的話,就too young too native了。由于UNICODE實(shí)際上是使用更多的字節(jié)來保存除英文外的其他國家的復(fù)雜語言文字,所以對于中文字符這樣的文字是非常合適的。比如,中文漢字的“中”字,用UNICODE編碼兩個(gè)字節(jié)就可以這樣表示:01001110 00101101,這樣一點(diǎn)問題都沒有。但如果是英文字母呢?本來英文字母只需要一個(gè)字節(jié)就可以表示,比如大寫字母A,用二進(jìn)制表示為0100 0001,而用UNICODE的話,就必須用0來補(bǔ)足多出來的一個(gè)字節(jié),即表示為00000000 01000001。大家看出問題所在了嗎?對了,對于英文來說,UNICODE編碼太浪費(fèi)空間了,足足大了一倍的空間。特別是在網(wǎng)絡(luò)上進(jìn)行傳輸時(shí),這種浪費(fèi)就極其明顯,會(huì)大大降低我們的傳輸效率。為了解決這個(gè)問題,就出現(xiàn)了一些中間格式的字符集,他們被稱為通用轉(zhuǎn)換格式,即UTF(Unicode Transformation Format)。而我們最常用的UTF-8就是這些轉(zhuǎn)換格式中的一種。UTF-8編碼其實(shí)是一種可“變長”的編碼格式,即把英文變長為1個(gè)字節(jié),而漢字用3個(gè)字節(jié)表示,特別生僻的還會(huì)變成4-6字節(jié)。所以如果是傳輸或存儲(chǔ)大量英文的話,UTF編碼格式優(yōu)勢非常明顯。

6. 不同編碼格式和UNICODE之間的轉(zhuǎn)換

為了在不同的編碼格式之間進(jìn)行轉(zhuǎn)換,我們必須對字符進(jìn)行編碼和解碼的工作。任何非UNICODE格式的字符(串),我們都可以使用decode方法將其解碼為UNICODE編碼的字符(串),這種轉(zhuǎn)換過程叫“解碼”。同樣道理,UNICODE格式的字符(串),也可以通過encode()方法將其編碼為其他編碼格式的字符(串),這個(gè)過程叫“編碼”。后面我們會(huì)頻繁使用到編碼和解碼的操作,大家都應(yīng)該明白什么時(shí)候應(yīng)該使用編碼,什么時(shí)候應(yīng)該解碼。

一文搞懂Python字符編碼問題,值得收藏

到此為此,大家應(yīng)該對編碼類型有一定了解了,總結(jié)一下就是:

1.為了處理英文字符,產(chǎn)生了ASCII碼。

2.為了處理中文字符,產(chǎn)生了GB2312。

3.為了處理各國字符,產(chǎn)生了Unicode。

4.為了提高Unicode存儲(chǔ)和傳輸性能,產(chǎn)生了UTF-8,它是Unicode的一種實(shí)現(xiàn)形式。

二、運(yùn)行環(huán)境的影響

搞清楚了上面介紹的各種編碼格式之后,接下來我們就開始詳細(xì)講解為什么會(huì)出現(xiàn)亂碼了。關(guān)于亂碼,大家記住兩個(gè)要點(diǎn):

(1)所謂亂碼的本質(zhì)是字符的編碼格式與顯示字符的環(huán)境編碼格式不一致引起的。這句話告訴我們要解決亂碼問題,我們需要知道兩個(gè)信息,一個(gè)是字符本身是什么編碼,另一個(gè)就是顯示字符的環(huán)境編碼是什么,兩者必須一致,才能顯示出正確的內(nèi)容。

(2)由于Unicode編碼是標(biāo)準(zhǔn)編碼格式,也可以看做是沒有任何特定編碼格式的“無編碼”模式。所以,對于任何Unicode類型編碼的字符,打印時(shí)python會(huì)自動(dòng)根據(jù)環(huán)境編碼轉(zhuǎn)為特定編碼后再顯示。

上面兩個(gè)要點(diǎn)大家一定要記住,接下來,我們來看看字符在python代碼中是怎么被編碼的。在不同的python版本中,字符編碼的方式也不一樣。先來說說比較麻煩的py2版本。如果你用py2來寫腳本的話,因?yàn)槟J(rèn)py2是用ascii來編碼腳本的,所以如果你的腳本中出現(xiàn)了中文,就必須在腳本的開始位置注明支持中文的編碼格式,否則會(huì)報(bào)錯(cuò)。所有支持中文的編碼格式都是可以的,比如聲明為#coding:utf8或#coding:gbk都是可以的。注明以后,我們就可以在腳本中隨意使用中文了。例如下面這個(gè)例子:

一文搞懂Python字符編碼問題,值得收藏

聲明編碼格式#coding:utf8或#coding:gbk以后可以正常工作。如下:

一文搞懂Python字符編碼問題,值得收藏

在py2中,所有字符串的編碼方式默認(rèn)是用ascii來進(jìn)行編碼的,如果通過coding:xxx的方式聲明了腳本的編碼方式,則字符串會(huì)按照聲明的字符編碼格式來進(jìn)行編碼,而字符串變量類型是為str類型的。這里大家要記住py2中str一定是有特定編碼的,不是Unicode格式(這里為什么要講這一句,因?yàn)榇龝?huì)介紹的py3字符串默認(rèn)是Unicode編碼的,待會(huì)我們會(huì)細(xì)講)。比如上面的a變量中保存的“中國”這兩個(gè)中文字符的編碼就是gbk格式了。那么當(dāng)我們打印這個(gè)a變量的時(shí)候,會(huì)出現(xiàn)什么情況呢?我們現(xiàn)在IDE中打印來看看,比如pycharm,打印出來結(jié)果如下。納尼?居然出現(xiàn)了亂碼,這是為什么呢?

一文搞懂Python字符編碼問題,值得收藏

如果記住了我之前說的關(guān)于亂碼的那兩個(gè)要點(diǎn)的同學(xué),應(yīng)該很容易明白這里為什么會(huì)出現(xiàn)亂碼。原因很簡單,這里a變量的編碼是gbk的,而我們運(yùn)行腳本的編輯器pycharm設(shè)置的環(huán)境編碼卻是utf8,兩者編碼方式并不一致,所以必定會(huì)出現(xiàn)亂碼。那么怎么解決呢?解決方式有幾種,一種是修改#coding:gbk為#coding:utf8,二是可以在'中國'前面加一個(gè)u,即a=u'中國'。在前面加u是將“中國”強(qiáng)制轉(zhuǎn)換為unicode編碼,即“無編碼”,此時(shí)變量的type將會(huì)變?yōu)閡nicode。前面已經(jīng)說過,對于unicode編碼的字符,python將自動(dòng)根據(jù)環(huán)境編碼進(jìn)行顯示,所以也就是會(huì)自動(dòng)幫我們編碼為utf8進(jìn)行顯示。還有一種方式是通過encode和decode函數(shù),比如像下面:

一文搞懂Python字符編碼問題,值得收藏

使用decode方法可以將字符串進(jìn)行解碼,解碼后格式就是Unicode了,所以a.decode('gbk')這句跟u"中國"效果是等價(jià)的,打印出來當(dāng)然是沒問題的。當(dāng)然,我們也可以明確寫出要編碼的類型,比如a.decode('gbk').encode('utf8'),這樣將Unicode明確地編碼為utf8,也是一樣的效果。這里大家要注意一點(diǎn),我們對所有非Unicode類型的字符只能進(jìn)行decode操作,不能進(jìn)行encode操作。對Unicode類型的只能是encode而不能decode,這個(gè)大家要注意。

搞明白了pycharm里面的行為后,我們再看看如果這個(gè)腳本不是在pycharm里面運(yùn)行,而是直接在命令行里面運(yùn)行,又會(huì)發(fā)生什么問題呢?就將就上面這個(gè)文件,我們在命令行里面運(yùn)行,結(jié)果如下:

一文搞懂Python字符編碼問題,值得收藏

果不其然,b1正常顯示了,b2卻出現(xiàn)了亂碼。這次出現(xiàn)亂碼的原因又是什么呢?這里大家要知道,命令行里面的環(huán)境編碼是gbk格式,由于b1是Unicode編碼,Unicode編碼的字符會(huì)自動(dòng)隨著環(huán)境編碼來輸出,所以不管在什么環(huán)境下,b1都能正常顯示輸出。而b2由于被encode成了utf8格式,所以它只能在環(huán)境編碼為utf8的環(huán)境中才能正常顯示,在命令行這種環(huán)境下就會(huì)出現(xiàn)由于編碼不一致而導(dǎo)致的亂碼。大家可以試試直接print a,由于文件是coding:gbk的,所以a是可以直接正常顯示的。比如代碼如下:

一文搞懂Python字符編碼問題,值得收藏

在pycharm中無法正常顯示a的值,但在命令行中卻可以,如下圖:

一文搞懂Python字符編碼問題,值得收藏

如果是py3的腳本的話,則要簡單得多。因?yàn)閜y3中,所有的字符串不再受系統(tǒng)環(huán)境編碼的影響,統(tǒng)一使用Unicode來進(jìn)行編碼,類型統(tǒng)一為str,所以不再需要在中文前面加u來使中文字符變?yōu)閁nicode這種寫法。而且所有py3的腳本默認(rèn)都是utf8來編碼的,所以我們也不需要在腳本開頭指定coding:xxxx了。打印顯示的時(shí)候也會(huì)方便很多,由于是字符串都是Unicode格式,所以不管在命令行中還是pycharm中,都會(huì)正常顯示而不會(huì)出現(xiàn)亂碼。

上面是通過腳本來運(yùn)行的情況,那么如果是直接在命令行中寫腳本,又會(huì)出現(xiàn)什么問題呢?其實(shí)不管在哪里運(yùn)行,上面說的兩個(gè)原則始終不變,大家永遠(yuǎn)記住無非我們就是要弄清楚字符本身的編碼和環(huán)境編碼,只要這兩者一致了,那一定不會(huì)出現(xiàn)亂碼。在python shell(即命令行)中直接寫代碼運(yùn)行時(shí),大家只需注意在windows下,命令行的默認(rèn)編碼是gbk的,而在Linux環(huán)境下,命令行的默認(rèn)編碼是utf8的,其他沒什么區(qū)別。所以我們接下來分別來看看。

在windows環(huán)境下,我們在命令行中寫一段代碼來看看,運(yùn)行效果如下:

一文搞懂Python字符編碼問題,值得收藏

大家注意,第一行我們在定義a="中國"時(shí),并不會(huì)報(bào)錯(cuò),因?yàn)樵诿钚兄心J(rèn)是gbk編碼,所以此時(shí)其實(shí)a的編碼已經(jīng)是gbk了,支持中文沒有任何問題。直接顯示a變量時(shí),打印出來的不是亂碼,而是該字符串的字節(jié)碼表示方式,大家可以理解成給計(jì)算機(jī)看的,不是給人看的,只有print出來的內(nèi)容才是給人看的。print a也不會(huì)報(bào)錯(cuò),因?yàn)榘凑誫bk方式編碼并且在gbk環(huán)境中運(yùn)行,不可能會(huì)出問題。下面直接將a進(jìn)行decode解碼時(shí),解碼方式必須跟編碼方式是一致的,所以gbk方式編碼的內(nèi)容不能解碼為utf8格式,只能decode為gbk。decode之后,字符串會(huì)變?yōu)閁nicode,也可以正常顯示。最后,我們將Unicode編碼為utf8時(shí),字符的編碼格式又跟環(huán)境編碼不一致了,所以再次出現(xiàn)了亂碼。py3同理,就不再贅述了,如果掌握了之前說的原則,應(yīng)該完全不會(huì)出現(xiàn)問題。如果是在Linux下面的命令行中運(yùn)行,道理也是一樣,只是需要注意linux下命令行默認(rèn)的編碼格式是utf8的就可以了。

看完上面的內(nèi)容,我相信大家應(yīng)該已經(jīng)掌握了字符編碼的所有秘密。不管編碼格式是什么,在什么地方執(zhí)行,大家始終記住那兩個(gè)關(guān)于亂碼的原則,問題一定會(huì)迎刃而解。接下來,我們再看看更多實(shí)際的例子。

比如,我們在使用爬蟲爬取網(wǎng)頁時(shí),也會(huì)經(jīng)常遇到亂碼,如果結(jié)合上面講的原則,大家是否能夠知道問題出在哪,并且解決這些問題呢?我們以網(wǎng)易和百度這兩個(gè)網(wǎng)站為例,給大家看看會(huì)有什么樣的問題。首先來看看網(wǎng)易的首頁,打開源碼,我們可以看到,網(wǎng)頁首頁的編碼格式是gbk的。

一文搞懂Python字符編碼問題,值得收藏

編碼格式gbk意味著,如果我們需要對抓取的網(wǎng)頁內(nèi)容進(jìn)行解碼的話,必須指定解碼方式為gbk才能正常解碼為Unicode類型的字符串。假定我們使用的是py3,如果使用默認(rèn)的decode()方法,將默認(rèn)解碼為utf8,肯定是會(huì)報(bào)錯(cuò)的。比如下面的代碼,我們先抓取163的首頁內(nèi)容,并用正則取出頁面的title,代碼如下:

一文搞懂Python字符編碼問題,值得收藏

這里為什么會(huì)報(bào)錯(cuò)呢?因?yàn)閞esp.content實(shí)際上是抓取的網(wǎng)頁的原始字符串,是以gbk編碼的二進(jìn)制內(nèi)容,所以我們需要知道這個(gè)字符串的編碼方式才能正確地進(jìn)行解碼。從網(wǎng)頁中我們可以知道,該網(wǎng)頁的編碼為gbk編碼方式,所以我們decode時(shí)必須指定gbk作為解碼的方式(如果decode中不指定解碼方式的話,默認(rèn)以utf8來解碼),所以我們應(yīng)該改為下面這樣就可以正確拿到我們的結(jié)果:

一文搞懂Python字符編碼問題,值得收藏

而對于百度首頁,其網(wǎng)頁編碼方式是utf8的,所以我們在解碼時(shí)就不用再專門指定utf8格式了,直接decode即可,大家可以自己試試。

本文到這里終于可以結(jié)束了,內(nèi)容確實(shí)不少,因?yàn)橐忝靼拙幋a的問題,我們需要知道很多東西,這是我們必須要掌握的。另外,很多資料和書籍上都會(huì)寫到,在py2的腳本中指定編碼方式時(shí),必須在腳本開頭的位置寫coding:utf8,想必大家讀完此文應(yīng)該知道這種說法是對的還是錯(cuò)的了。這就是學(xué)習(xí)的價(jià)值,為什么我們要摳原理、抓本質(zhì),就是讓我們有足夠的能力和底氣去判斷和質(zhì)疑一個(gè)問題的對和錯(cuò),只有這樣,你的技術(shù)才能真正進(jìn)步,讓你去解決?更多的問題。最后,希望大家以后再也不會(huì)受到亂碼問題的困擾了。?

分享到:
標(biāo)簽:字符 編碼 Python
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定