Unicode 編碼

為了介紹 Python 的編碼知識,我們先來回顧下計算機發展歷史上文字是如何編碼的。

計算機在美國被髮明之後,一開始需要被儲存的字元個數不多,包括大小寫的英語字母以及常用的標點符號,在 7 個 bit 內就能把所有的適用於美國當時要求的字元給列舉出來,這就是 ASCII 碼,是 American Standard Code for Information Interchange 的首字母縮寫。

計算機繼續推廣後,在文字記錄上首先遇到的問題就是即使是跟英語相近的語言,比如法語等,它們有很多的字母需要在正常的字母上方加上比如冒號等符號,例如éÍ ,那 7 個 bit 就不夠用了。於是各個語言就開始在 ASCII 的基礎上擴充,擴充到了一個位元組,也就是 8 個 bit。法語加上法語自己的一些特殊字母成了一個新的編碼集,俄語加上自己的西裡爾字母也成了一個新的編碼集。這些嘗試在自己語言內部是沒有問題,但是一個文件中需要混合兩種以上的語言時候,就出現錯誤了,沒有一個編碼集能夠覆蓋全部語言。

這就是後來為什麼又把編碼擴充到了兩個位元組,或者 16 個 bit 的原因,用一個超大的編碼集把所有的文字都包含進來,這種努力直到字符集的長度變為了 21 個 bit,也就是字元編碼的範圍從 00x10FFFF,才真正的把世界上所有的文字都囊括進去了。最後的這個編碼標準,就是 ISO 10646,或者也可以說是 Unicode

回顧完了歷史,我們來看什麼是 UTF-8。現有的 ISO10646 解決了編碼的終極問題,任何字元都可以在這個編碼集中找到自己的位置,但是如果我們用這種方法來儲存文字的話,就會有一個問題了,太浪費空間。因為常用的字元都可以在 8 個位元或者 16 個位元內找到自己的位置,假如我們都有 21 個位元來儲存字元的話,效率大概只有 30%-50%,所有就出現了類似 UTF-8 這樣的編碼,它也是現行被採用最多的編碼方式。

UTF-8UTF 的意思是 Unicode Transformation Format-Unicode 轉換格式,8 的意思是 8 位元編碼。它的規則如下,

  1. 假如編碼數字<128,就採用用相應的編碼值。
  2. 假如編碼數字>128,就分別用 2、3 或 4 個位元組來表示,其中每個位元組的取值範圍在 128-255,也即是最高位都為 1,是為了跟 ASCII 區分開,ASCII 的位元組最高位 bit 是 0

Python 3 以後,字串儲存都是以 unicode 的方式來儲存了,而不像 Python 2 中那樣字串是預設以 bytes 來儲存的。

# Python 3
type("f") == type(u"f")  # True, <class 'str'>
type(b"f")               # <class 'bytes'>

# Python 2
type("f") == type(b"f")  # True, <type 'str'>
type(u"f")               # <type 'unicode'>