1分鐘讓你搞懂python中的編碼!專門給小白寫的一篇文章
很多初學者會被Python中UnicodeDecodeError弄得一頭汙水,相信你也一定遇到過這個問題,這裡我們講一下編碼相關的知識。 (部分內容參考了 《編寫高質量Python程式碼的59個有效方法》一書 )
1. 原理:
加群943752371即可獲取十套PDF和大量學習資料
計算機中所有的內容都是用1和0組成的(二進位制)。 這和計算機的硬體實現原理相關,通常組成計算機的邏輯電路只有接通和斷開兩個狀態,分別用來表示1和0。這樣一個邏輯電路組成的位置叫一個位元(bit),一個位置能表示的內容有限,但組合起來,多個一起用就能發揮出無限威力,我們把8位放到一起組成一個 位元組(Byte)
ASCII 碼使用指定的 7 位 或 8 位二進位制數組合來表示 128 或 256 種字元。 標準ASCII 碼也叫基礎ASCII碼,使用 7 位二進位制數(最開始的那1位固定為0) (
有了這個編碼表,在計算機中處理大小英文,數字,標點基本上夠用了,但問題是我們的中文有非常多漢字,總數超過了8萬,常用的都有3500個之多,更何況世界上還有各種其它語言,那麼在計算機中怎麼表示數量這麼龐大的字元呢?
解決這個問題很簡單,每個字元用多個位元組來表示,一個不夠用兩個,兩個不夠用三個,使用足夠多的位元組肯定是能表示出來的。使用這種“原始”的多個位元組值表示其它的複雜字元,這些8位稱為 原始8位值。
但問題又來了,各平臺,各國家規定都不統一,同樣的編碼,在一個國家表示某個文字,在另一個國家可能被用來表示另一個文字,在資訊交流的時候經常會出現“亂碼”。為了解決這個問題,必須得有統一的標準,於是Unicode(統一碼、萬國碼、單一碼)就誕生了。Unicode 也稱為 UCS(Universal Coded Character Set: 國際編碼字元集合) 是一個字元集合。UNICODE標準也在不斷髮展完善,目前使用 4個位元組 表示一個字元可以表示出全世界所有字元。那UNICODE在計算機中如何儲存呢,儲存時也必須佔用4個位元組麼,這就要涉及到編碼的知識。
UNICODE最常見的編碼方式是UTF-8 ,另外還有UTF-16,UTF-32等。如果每個字元都用四個位元組來儲存,純英文內容佔用空間變成了原來ASCII的四倍,非常浪費空間。而UTF-8編碼比較巧妙,採用的是變長的方法,也就是一個字元在UTF-8編碼表示時佔用1個位元組到4個位元組不等,相容ASCII,表示純英文時,並不會佔用更多長度。
2. 轉換過程
UTF-8,GBK等,通過 解碼(decode) 得到UNICODE,UNICODE通過 編碼(encode) 可以轉換成GBK或UTF8等編碼( 原始8位值 ),轉換如下圖所示。
3. 示例:
u'6啊'.encode('utf8') -> b'6\xe5\x95\x8a'(16進製表示的 原始8位值 )
u'6啊'.encode('gbk') -> b'6\xb0\xa1' (16進製表示的 原始8位值 )
從上面的例子可以看到6是用一個位元組表示的,漢字“啊”在utf8中是用三個位元組表示的(gbk中是兩個位元組),其中\xe5意思就是16進位制的e5,代表一個8位二進位制:
bin(int('e5', base=16)) -> '0b11100101'。
再比如 “塗 ” 這個漢字,unicode 為 u'\u6d82'
使用utf8編碼時 '\xe6\xb6\x82' 11100110 10110110 10000010 三個8位
使用gbk編碼時 '\xcd\xbf' 11001101 10111111 兩個8位
4. 結論:
4.1 Unicode可以通過不同的字元編碼來實現,最常用的是utf8,它是ASCII碼的超集。
4.2 Python 3 有兩種表示字元序列的型別:bytes 和 str。bytes 的例項包含原始的8位值,str 的例項包含unicode字元。
4.3 Python 2 也有兩種表示字元序列的型別 ,分別叫做 str 和 unicode。與Python3不同的是,Python2中 str 例項包含原始的8位值;而unicode的例項,則包含unicode字元。Python2裡面 不夠嚴格 ,如果str只包含7位ASCII字元,那麼unicode和str例項似乎就成了同一種類型: a) 可以相加 b) 可以比較 c) 可以用 %s 格式化。如果使用的時候不注意在特定的場景下就會帶來問題。
4.4 在程式設計時,編碼和解碼儘量在最外圍做 ,程式處理邏輯中儘量全部使用unicode,當有必要時( 比如寫入到檔案 )才 encode 轉換成utf8等編碼 。
從檔案等中讀取後儘快decode轉換成unicode。這樣可以大大減少編碼帶來的問題。
5. 讀者思考:
1. utf8為什麼這麼成功,它是如何相容ASCII的?
2. 通過上面的示例,是不是發現用gbk儲存中文比utf8更省空間,那為什麼一般情況下不用gbk來儲存,而是用utf8呢?