python unicode 編碼整理

發表於2016-10-24

unicode 與 utf-8 的關係

unicode 是 character set

  • character set 是把每個字元對應成數字的集合,比如unicode中 A對應0041,漢字『我』對應 ‘6211’
  • unicode 是個很大的集合,幾乎覆蓋世界上所有的字元,現在的規模已經可以容納100萬個字元。

utf-8 是對 unicode 儲存的實現方式

unicode 只定義字元對應的數字,但沒有規定這些數字如何儲存起來,比如像中文的『我』字儲存時需要兩個位元組來表示,而英文字母A卻只需要一個位元組,有些其他的字元可能需要3-4個位元組。

  • 如果統一規定每個字元用3個或者4個位元組來儲存,那麼每個英文字元都必然需要額外2到3個0,這對儲存是很大的浪費。
  • 如果每個字元按照實際需要的位元組數來儲存,計算機就分不清三個位元組是表示三個字元還是一個字元。

utf-8 是對 unicode 編碼儲存的一種實現方式,同樣的還有 utf-16, utf-32。

utf-8 是使用最廣泛的編碼方式,採用變長的編碼方式,可以使用1-4個位元組來表示一個字元; utf-16 用2個或4個位元組,utf-32 用4個位元組表示。編碼規則如下:

  1. 對於單位元組的符號,位元組的第一位設為0,後面7位為這個符號的unicode碼。因此對於英語字母, UTF-8編碼和ASCII碼是相同的。
  2. 對於n位元組的符號(n>1),第一個位元組的前n位都設為1,第n+1位設為0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進位制位,全部為這個符號的unicode碼。

python2 中的 str 和 unicode

python2 中有字串型別有兩種:byte string (str)unicode string (unicode)

上面的輸出中,第一個s的型別是 str,列印出來的內容是 utf-8 編碼過的內容。第二個s的型別是 unicode,列印出來的兩個雙位元組的數字分別表示了兩個漢字『美的』。

encodedecode提供 str 和 unicode 這兩種的型別的互相轉化。

  • encode 把 unicode 轉化成 str(byte string)
  • decode 把 str(byte string) 轉化成 unicode

本質上,str是存放的位元組序,有可能是 ascii, gbk, utf-8 等等中的任意一種,通過呼叫 decode 可以把他們轉化成 unicode ,預設的 decode 編碼是 ascii 。str中到底是用的哪一種編碼,取決於它所在的場景,跟 locale ,檔案編碼等等都有關係。

文字檔案、編輯器的處理

比如上面的檔案enc.py,儲存的時候選擇檔案編碼是GBK,程式檔案本質上也是檔案,當我們使用某個外部的應用 開啟它時(編輯器或者python直譯器等),外部應用是不知道該檔案的編碼格式的,

這個時候有三種情況:

  • 應用使用其預設的編碼方式去解析,比如UTF-8或者ASCII;python直譯器預設是ASCII,編輯器可以自己設定;
  • 應用根據檔案中的位元組內容,自動檢測編碼方式;
  • 文字檔案告訴應用使用什麼編碼方式去解碼;比如# -*- coding: GBK -*-告知直譯器使用GBK來解碼;

試驗一下,把# -*- coding: GBK -*-刪除後,執行python enc.py,輸出:

試著用vim開啟該檔案時,『中文』兩個字就會顯示成亂碼,因為vim預設的檔案編碼方式被設定成UTF-8了。

輸出結果:

從這裡可以看出來, s2中存放的是byte格式的從檔案中讀到的GBK編碼的內容。

再看下面的這段程式碼,程式檔案utf8_enc.py,儲存成UTF-8編碼的。

輸出:

這裡同樣可以知道,s2中存放的是檔案儲存的編碼UTF-8的byte碼。

References

http://www.rrn.dk/the-differe…
http://www.ruanyifeng.com/blo…
https://docs.python.org/2/how…
http://yergler.net/2012/bytes…

相關文章