編碼的秘密(python版)
編碼(Python版)
最近在學習Python的過程中,被不同的編碼搞得有點暈,于是看了前人的留下的文檔,加上自己的理解,準備寫下來,分享給正在為編碼苦苦了掙扎的你。
編碼的概念
編碼就是將信息從一種格式轉換成另一種格式,計算機只認識二進制,簡單的理解,將我們眼睛看到的文字轉換為計算機能夠識別的二進制格式視為編碼,而二進制以某種編碼格式轉換為我們能看的文字的過程可以看成是解碼。既然計算機只能認識二進制0,1,那么我們用的字母、數字和文字等是怎樣和他們對應的呢?那就請繼續看吧!
Python中查看默認的編碼規范是:
ASCⅡ碼
我們都知道計算機是米國發明的,起初的時候也只有米國那些國家使用,而他們的語言僅僅只有26個字母組成,再加上一些符號,所以在一開始的時候,用的編碼規則就是ASCⅡ碼。ASCⅡ,中文名叫美國信息交換標準代碼,因為名叫American Standard Code for Information Interchange,下面我們來看看ASCⅡ表:
ASCⅡ碼用一個字節,也就是8位二進制組來標識一個字符,比如00100001就代表字符?!,第一版的ASCⅡ沒有用到最高的一個bit,所以取值范圍為0-127,只能表示128字符。為了滿足西歐等國家的字符要求,于是用上了最高位的bit,能表示的字符也從128增加到了256個。
在Python中使用函數ord(),可以字符轉換為對應數值,使用函數chr可以將數值轉換為對應字符:
GB2312和GBK
當計算機漂洋過海來到了中國,ASCⅡ已經不能滿足我大天朝的需求了,常用的漢字大致都有2k-3k。所以中國國家標準總局在1980發布了《信息交換用漢字編碼字符集》,也就是GB2313標準。GB2312一共收錄了7445個字符(6763個漢字和682個其他符號),包括拉丁字母、希臘字母和日文平假名等,基本上滿足了國人的需求。
在GB2312中每個漢字使用兩個字節來表示,分為高字節和低字節,漢字區高字節從B0-F7,低字節從A1-FE,占用的碼位是72*94=6768,其中有5個空位是D7FA-D7FE,規定第一個字節大于127的就代表這是一個漢字的開始(這一個字節和下一個字節就代表一個漢字),?每個字節的最高位都位1。
但是對于人名、古漢語等方面出現的罕用字,GB2312不能處理,后來就出現了GBK。GBK向下兼容GB2312,其編碼范圍從8140到FEFE(不包括xx7F),共23940個碼位,共收錄了21003個漢字,這還是很厲害的了?,F在我們使用的計算機默認的就是GBK編碼。
Unicode和UTF-8
我們國家搞出了GBK,其他的國家也搞出了各種各樣的編碼,比如小日本的SJIJ,寶島臺灣的BIG5,國際組織一看,這不行啊,每個地方都各自搞各自的,那么在不同的國家之間就會出現不兼容,我用GBK編碼格式寫的軟件,弄到你編碼格式為SJIJ的計算機就不能執行了。所以就出現了Unicode,也稱萬國碼。unicode是用2個字節來表示一個字符的,65536類個字符,這足以覆蓋世界上所有的文字。
這樣雖好,但是美國人民就不開心了,我一個字母,比如'a'就需要占用一個字節,現在需要占用兩個字節,這樣就大大的浪費了內存和硬盤的空間,所有后來就出現了UTF-32,UTF-16和UTF-8,前兩個這里就不在敖述了,現在并不常用,我們這看看這個UTF-8,UTF-8是一種可變長的編碼格式,存儲英文字母只需要一個字節,存儲漢字需要3個字節,但超大字符集中的更大多數漢字要占4個字節。我們在內存里面的數據是unicode,在傳輸數據和保存數據的時候適用UTF-8已節省空間和帶寬。
Python2的編碼
在Python2中默認的編碼是ASCII,Python2的字符串類型有兩種:str和Unicode,這兩個只是字符串類型的名字,我們主要看它們在內存里面的內存地址:
在Python2中,str類型字符串類型在內存中存儲的是bytes數據,Unicode類型字符串在內存中存儲的是unicode數據。那兩種數據之間是什么關系了?這里就涉及到了解碼(encode)和編碼(decode)了。
由上運行結果可知,unicode轉換為bytes數據的過程是編碼。從bytes數據轉換為unicode數據的過程是解碼。我們再來看一下:
我們可以看到得到一堆亂文,name存在內存里的時候是以UTF編碼成的bytes數據,而我們這里decode('big5')使用big5來解碼,雖然成功了,但是輸出結果卻不是我們想要的結果。
當我們把第一行coding改為big5的時候就不會出現亂文了,
所以我們用什么規則編碼的就要用什么區解碼!
注意:我們在終端顯示出來的明文,就是你用戶所看到的,其實都是已經轉換成unicode到內存里面,而bytes數據一般都是計算機識別的。
Python3的編碼
在Python3中也定義了2種類型的字符串類型,str和bytes,str類型存儲unicode數據,bytes類型存儲bytes數據。
如上運行結果,bytes轉換為unicode為解碼,uicode轉為bytes數據類型為編碼。
由上圖所示,在不同的編碼之間轉換的時候,我們都要經過unicode這個中轉站,沒辦法,雖然unicode老大哥強大呢,當我們想把utf-8編碼的數據轉換為gbk的,我們就需要把utf-8的數據先解碼成unicode,再由unicode編碼成gbk。
在py2和py3中有個重要的區分就是,py2會自動把bytes數據解碼成unicode,而py3就不會自動把bytes解碼成unicode了。所以說py3更清晰的區分了bytes數據和unicode。
一個.py文件的"一生"
那我們創建.py文件,到執行.py文件,這里面的編碼和解碼是怎么來的呢?
1.當我們創建一個.py文件的時候,會有一個默認的編碼格式(這里以pycharm為例),在右下角,默認是UTF-8,當然你也可以選擇其他的編碼:
2.當我們在.py文件里面寫入代碼的時候,會以unicode的編碼格式保存在內存中;
3.當我們保存的時候,會將Unicode數據編碼成utf-8格式的數據,然后保存在硬盤里面;
4.當我們執行文件的時候,pycharm會調用Python的解釋器來讀取文件,在py2中,默認會以ASCII將代碼解碼成unicode數據,但是ASCII碼并不認識中文,所以就會出現報錯。
所以,在py2中,我們需要加上:
但是在py3中就不存在這個問題了,只要編碼的時候適用的是UTF-8,Python3默認的編碼規范就是UTF-8,它會用UTF-8來將UTF-8的bytes數據解碼成unicode,然后在計算機終端顯示!