UTF-8

1. Unicode和UTF-8
爲了統一全世界各國語言文字和專業領域符號(例如數學符號、樂譜符號)的編碼,ISO制定了ISO 10646標準,也稱爲UCS(Universal Character Set)。UCS編碼的長度是31位,可以表示231個字符。如果兩個字符編碼的高位相同,只有低16位不同,則它們屬於一個平面(Plane),所以一個平面由216個字符組成。目前常用的大部分字符都位於第一個平面(編碼範圍是U-00000000~U-0000FFFD),稱爲BMP(Basic Multilingual Plane)或Plane 0,爲了向後兼容,其中編號爲0~256的字符和Latin-1相同。UCS編碼通常用U-xxxxxxxx這種形式表示,而BMP的編碼通常用U+xxxx這種形式表示,其中x是十六進制數字。在ISO制定UCS的同時,另一個由廠商聯合組織也在着手製定這樣的編碼,稱爲Unicode,後來兩家聯手製定統一的編碼,但各自發布各自的標準文檔,所以UCS編碼和Unicode碼是相同的。

有了字符編碼,另一個問題就是這樣的編碼在計算機中怎麼表示。現在已經不可能用一個字節表示一個字符了,最直接的想法就是用四個字節表示一個字符,這種表示方法稱爲UCS-4或UTF-32,UTF是Unicode Transformation Format的縮寫。一方面這樣比較浪費存儲空間,由於常用字符都集中在BMP,高位的兩個字節通常是0,如果只用ASCII碼或Latin-1,高位的三個字節都是0。另一種比較節省存儲空間的辦法是用兩個字節表示一個字符,稱爲UCS-2或UTF-16,這樣只能表示BMP中的字符,但BMP中有一些擴展字符,可以用兩個這樣的擴展字符表示其它平面的字符,稱爲Surrogate Pair。無論是UTF-32還是UTF-16都有一個更嚴重的問題是和C語言不兼容,在C語言中0字節表示字符串結尾,庫函數strlen、strcpy等等都依賴於這一點,如果字符串用UTF-32存儲,其中有很多0字節並不表示字符串結尾,這就亂套了。

UNIX之父Ken Thompson提出的UTF-8編碼很好地解決了這些問題,現在得到廣泛應用。UTF-8具有以下性質:

編碼爲U+0000~U+007F的字符只佔一個字節,就是0x00~0x7F,和ASCII碼兼容。

編碼大於U+007F的字符用2~6個字節表示,每個字節的最高位都是1,而ASCII碼的最高位都是0,因此非ASCII碼字符的表示中不會出現ASCII碼字節(也就不會出現0字節)。

用於表示非ASCII碼字符的多字節序列中,第一個字節的取值範圍是0xC0~0xFD,根據它可以判斷後面有多少個字節也屬於當前字符的編碼。後面每個字節的取值範圍都是0x80~0xBF,見下面的詳細說明。

UCS定義的所有231個字符都可以用UTF-8編碼表示出來。

UTF-8編碼最長6個字節,BMP字符的UTF-8編碼最長三個字節。

0xFE和0xFF這兩個字節在UTF-8編碼中不會出現。

具體來說,UTF-8編碼有以下幾種格式:

U-00000000 – U-0000007F:  0xxxxxxx
U-00000080 – U-000007FF:  110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

第一個字節要麼最高位是0(ASCII字節),要麼最高兩位都是1,最高位之後1的個數決定後面有多少個字節也屬於當前字符編碼,例如111110xx,最高位之後還有四個1,表示後面有四個字節也屬於當前字符的編碼。後面每個字節的最高兩位都是10,可以和第一個字節區分開。這樣的設計有利於誤碼同步,例如在網絡傳輸過程中丟失了幾個字節,很容易判斷當前字符是不完整的,也很容易找到下一個字符從哪裏開始,結果頂多丟掉一兩個字符,而不會導致後面的編碼解釋全部混亂了。上面的格式中標爲x的位就是UCS編碼,最後一種6字節的格式中x位有31個,可以表示31位的UCS編碼,UTF-8就像一列火車,第一個字節是車頭,後面每個字節是車廂,其中承載的貨物是UCS編碼。UTF-8規定承載的UCS編碼以大端表示,也就是說第一個字節中的x是UCS編碼的高位,後面字節中的x是UCS編碼的低位。

例如U+00A9(©字符)的二進制是10101001,編碼成UTF-8是11000010 10101001(0xC2 0xA9),但不能編碼成11100000 10000010 10101001,UTF-8規定每個字符只能用儘可能少的字節來編碼

2. Python的ASCII, GB2312, Unicode , UTF-8
ASCII 是一種字符集,包括大小寫的英文字母、數字、控制字符等,它用一個字節表示,範圍是 0-127 Unicode分爲UTF-8和UTF-16。
UTF-8變長度的,最多 6 個字節,小於 127 的字符用一個字節表示,與 ASCII 字符集的結果一樣,ASCII 編碼下的英語文本不需要修改就可以當作 UTF-8 編碼進行處理。
Python 從 2.2 開始支持 Unicode ,函數 decode( char_set )可以實現 其它編碼到 Unicode 的轉換,函數 encode( char_set )實現 Unicode 到其它編碼方式的轉換。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章