Python2與Python3的編碼問題

一. 什么是編碼

將明文轉(zhuǎn)換為計算機(jī)可以識別的的編碼文本稱為“編碼”涂滴, 反之從計算機(jī)可識別的編碼文本轉(zhuǎn)回明文為“解碼”

1. ASCII

計算機(jī)上的數(shù)據(jù)都是以二進(jìn)制的形式存儲的,1個字節(jié)(8比特)可以表示256種狀態(tài),英文只有26個字符寸癌,再加上一些特殊字符,使用128個就夠了弱贼,計算機(jī)就可以使用127個不同字節(jié)來存儲英語文字蒸苇,這就是ASCII編碼

最開始的時候8位中的最高位是沒有用到的,后來為了表示拉丁文吮旅,將最高位用上形成擴(kuò)展ASCII編碼溪烤,一個字節(jié)就用滿了味咳。

2. GB2312

計算機(jī)進(jìn)入中國后,無法顯示中文檬嘀,一個自己已經(jīng)被占滿了槽驶,我國重新制定了一個編碼表,將擴(kuò)展的第八位對應(yīng)的拉丁文全部刪掉鸳兽,規(guī)定一個小于127的字符與原來的意義相同掂铐,當(dāng)兩個大于127的字符鏈接在一起的時候,就表示一個漢字揍异,前面一個字節(jié)為高字節(jié)(0xA1-0xF7)全陨,后面一個字節(jié)為低字節(jié)(0xA1-0xFE),這樣可以表示7000多個漢字衷掷,這種編碼叫做GB2312辱姨。GB2312是對ASCII的中文擴(kuò)展

3. GBK和GB18030

由于漢字的數(shù)量太大,GB2312不能滿足需求戚嗅,后來規(guī)定只要第一個字節(jié)大于127就固定表示一個漢字雨涛,不管后面的是不是擴(kuò)展字符集里面的內(nèi)容,擴(kuò)展后的編碼成為GBK, GBK包括了GB2312的所有內(nèi)容渡处,同時增加了近20000個新的漢字(包括繁體)和符號

4. Unicode

在Unicode出現(xiàn)之前镜悉,每個國家都搞自己的編碼,彼此之間互不支持医瘫,帶來很多麻煩,國際標(biāo)標(biāo)準(zhǔn)組織提出來一個統(tǒng)一的編碼標(biāo)準(zhǔn):Unicode

Unicode用兩個字符來表示一個字符旧困,可以提供65535種字符醇份,足夠覆蓋世界上的所有符號

5. utf-8

Unicode的出現(xiàn),提供了統(tǒng)一的標(biāo)準(zhǔn)吼具,但對于英文世界的國家來說僚纷,一個字節(jié)完全夠用,如果使用Unicode會浪費(fèi)大量空間拗盒,為了解決這個問題提出了utf-8怖竭,一種針對Unicode的可變長度字符編碼,可以使用1-4個字節(jié)表示一個符號陡蝇,根據(jù)不同的符號變化字節(jié)長度痊臭,當(dāng)字符在ASCII編碼范圍時,用一個字節(jié)表示登夫,兼用ASCII广匙。

使用這樣的編碼的好處是,雖然內(nèi)存匯總的數(shù)據(jù)都是Unicode恼策,但當(dāng)數(shù)據(jù)保存到磁盤或者用于網(wǎng)絡(luò)傳輸時鸦致,使用utf-8會節(jié)省更多的流量和硬盤空間。

Unicode和utf-8的關(guān)系:Unicode是內(nèi)存編碼表示方案(規(guī)范),而utf-8是如何保存和傳輸U(kuò)nicode的方案(實(shí)現(xiàn))

二. Python2 中的sting編碼

在Python2中分唾,有兩種字符串類型:str類型和Unicode類型抗碰。這兩個類型只是Python定義的兩個名字,關(guān)鍵還要看這兩種數(shù)據(jù)類型在內(nèi)存中的存儲方式是什么绽乔。

>>> s1 = '中'
>>> print type(s1)
<type 'str'>
>>> print repr(s1)
'\xd6\xd0'

>>> s2 = u'中'
>>> print type(s2)
<type 'unicode'>
>>> print repr(s2)
u'\u4e2d'

由此可以看出strUnicode分別存儲的是字節(jié)數(shù)據(jù)Unicode數(shù)據(jù).那么這兩種數(shù)據(jù)之間的關(guān)系是什么樣的弧蝇?

>>> s1 = u'中'
>>> print repr(s1)
u'\u4e2d'
>>> 
>>> b = s1.encode('utf-8')
>>> print b
中
>>> print type(b)
<type 'str'>
>>> print repr(b)
'\xe4\xb8\xad'
>>> 
>>> s2 = '中國'
>>> u = s2.decode('utf-8')  
>>> print u
中國
>>> print type(u)
<type 'unicode'>
>>> print repr(u)
u'\u4e2d\u56fd'

s2的“中國”在Windows系統(tǒng)中需要使用gbk來解碼, 無論utf-8還是gbk都只是一種編碼編碼規(guī)則迄汛,一種把Unicode數(shù)據(jù)編碼成字節(jié)數(shù)據(jù)的規(guī)則捍壤。所以utf-8編碼的字節(jié)一定要utf-8解碼,否則亂碼或者報錯鞍爱。

# -*-coding:utf-8-*-

print '中國'  # 中國
print repr('中國')    # '\xe4\xb8\xad\xe5\x9b\xbd'

print (u'hello' + 'world')  # helloworld

print (u'中國' + '人民') #UnicodeDecodeError: 
                        #'ascii' codec can't decode byte 0xe4
                        #in position 0: ordinal not in range(128)

Python 2 悄悄掩蓋掉了 byte 到 unicode 的轉(zhuǎn)換鹃觉,只要數(shù)據(jù)全部是 ASCII 的話,所有的轉(zhuǎn)換都是正確的睹逃,一旦一個非 ASCII 字符偷偷進(jìn)入你的程序盗扇,那么默認(rèn)的解碼將會失效,從而造成 UnicodeDecodeError 的錯誤沉填。py2編碼讓程序在處理 ASCII 的時候更加簡單疗隶。付出的代價就是在處理非 ASCII 的時候?qū) ?/p>

三. Python3中的string編碼

python3 renamed the unicode type to str ,the old str type has been replaced by bytes.
** py3也有兩種數(shù)據(jù)類型:str和bytes; str類型存unicode數(shù)據(jù)翼闹,bytse類型存bytes數(shù)據(jù)斑鼻,與py2比只是換了一下名字而已。**
python3中將utf-8或者gbk等編碼的字節(jié)數(shù)據(jù)轉(zhuǎn)為Python3中的str類型猎荠, utf-8編碼的bytes <---> str
python2中將 utf-8或者gbk等編碼的str編解碼為Python2中的Unicode坚弱, utf-8編碼的str <---> unicode

Python3中的編碼思想

Python 3清晰地將文本和二進(jìn)制數(shù)據(jù)區(qū)分開了,不會對bytes字節(jié)串進(jìn)行自動解碼关摇。文本總是Unicode荒叶,由str類型表示,二進(jìn)制數(shù)據(jù)則由bytes類型表示输虱。Python 3不會以任意隱式的方式混用str和bytes些楣,將兩者明確地區(qū)分開∠芏茫基于此愁茁,Python3中不能拼接字符串和字節(jié)包,也不可以在字節(jié)包里搜索字符串(反之亦然)横堡,也不能向使用字符串參數(shù)的函數(shù)中傳入字節(jié)包參數(shù)(反之亦然)埋市。

四. 文件存儲讀取過程中的編碼問題

對于文本編輯器word等軟件,當(dāng)我們在這些軟件上編輯文字的時候命贴,無論是什么語言的文字或符號道宅,計算機(jī)都是無法識別的食听。
那么在保存之前數(shù)據(jù)是通過什么形式存在內(nèi)存的呢?
是unicode數(shù)據(jù)污茵,為什么要存unicode數(shù)據(jù)樱报,這是因?yàn)闊o論世界上的任何字符它都有唯一編碼對應(yīng),兼容性是最好的泞当。
當(dāng)我們保存了存到磁盤上的數(shù)據(jù)又是什么呢迹蛤?
是通過某種編碼方式編碼的bytes字節(jié)串。比如utf8---一種可變長編碼襟士,很好的節(jié)省了空間盗飒;還可以是gbk等編碼方式。
在我們的文本編輯器軟件都有默認(rèn)的保存文件的編碼方式陋桂,比如utf-8逆趣,gbk等。當(dāng)我們保存的時候嗜历,這些編輯軟件已經(jīng)"默默地"做了編碼工作宣渗。
那當(dāng)我們再打開這個文件時,軟件又默默地給我們做了解碼的工作梨州,將數(shù)據(jù)再解碼成unicode,然后就可以呈現(xiàn)明文給用戶了痕囱!
所以,unicode是離用戶更近的數(shù)據(jù)暴匠,bytes是離計算機(jī)更近的數(shù)據(jù)鞍恢。

編碼與程序運(yùn)行的關(guān)系

編寫Python代碼一般會用到sublime,pycharm每窖,vim等軟件有序。而代碼文件的創(chuàng)建、保存岛请、執(zhí)行等過程就伴隨著編解碼流程。下面以pycharm為例介紹這一過程警绩。
使用pycharm創(chuàng)建hello.py文件崇败,當(dāng)我們保存的的時候,hello.py文件就以pycharm默認(rèn)的編碼方式保存到了磁盤肩祥;關(guān)閉文件后再打開后室,pycharm就再以默認(rèn)的編碼方式對該文件打開后讀到的內(nèi)容進(jìn)行解碼,轉(zhuǎn)成unicode到內(nèi)存我們就看到了我們的明文混狠;
而如果我們點(diǎn)擊運(yùn)行按鈕或者在命令行運(yùn)行該文件時岸霹,Python解釋器這個軟件就會被調(diào)用,打開文件将饺,然后將存儲在磁盤上的bytes數(shù)據(jù)解碼成unicode數(shù)據(jù)贡避,這個過程和編輯器是一樣的痛黎,不同的是解釋器會再將這些unicode數(shù)據(jù)翻譯成C代碼再轉(zhuǎn)成二進(jìn)制的數(shù)據(jù)流,最后通過控制操作系統(tǒng)調(diào)用cpu來執(zhí)行這些二進(jìn)制數(shù)據(jù)刮吧,整個過程才算結(jié)束湖饱。
py2默認(rèn)ASCII碼,py3默認(rèn)的utf8杀捻,可以通過如下方式查詢

import sys
print(sys.getdefaultencoding())

使用Python2需要在編碼文件頭加一行#-*-coding:utf-8-*-井厌,是因?yàn)槿绻鹥y2解釋器去執(zhí)行一個utf8編碼的文件,就會以默認(rèn)地ASCII去解碼utf8致讥,一旦程序中有中文仅仆,自然就解碼錯誤了,所以我們在文件開頭位置聲明一下告訴解釋器不要以默認(rèn)的編碼方式去解碼這個文件垢袱,而是以utf8來解碼墓拜。
而Python3的解釋器因?yàn)槟J(rèn)utf8編碼,不存在這樣的問題惶桐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撮弧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子姚糊,更是在濱河造成了極大的恐慌贿衍,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件救恨,死亡現(xiàn)場離奇詭異贸辈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)肠槽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門擎淤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秸仙,你說我怎么就攤上這事嘴拢。” “怎么了寂纪?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵席吴,是天一觀的道長。 經(jīng)常有香客問我捞蛋,道長孝冒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任拟杉,我火速辦了婚禮庄涡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搬设。我一直安慰自己穴店,他們只是感情好撕捍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迹鹅,像睡著了一般卦洽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斜棚,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天阀蒂,我揣著相機(jī)與錄音,去河邊找鬼弟蚀。 笑死蚤霞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的义钉。 我是一名探鬼主播昧绣,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捶闸!你這毒婦竟也來了夜畴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤删壮,失蹤者是張志新(化名)和其女友劉穎贪绘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體央碟,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡税灌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亿虽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菱涤。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洛勉,靈堂內(nèi)的尸體忽然破棺而出粘秆,到底是詐尸還是另有隱情,我是刑警寧澤收毫,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布翻擒,位于F島的核電站,受9級特大地震影響牛哺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劳吠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一引润、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痒玩,春花似錦淳附、人聲如沸议慰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽别凹。三九已至,卻和暖如春洽糟,著一層夾襖步出監(jiān)牢的瞬間炉菲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工坤溃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拍霜,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓薪介,卻偏偏與公主長得像祠饺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子汁政,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容