05 Unicode

代碼點

Unicode標準的本意很簡單:希望給世界上每一種文字系統的每一個字符,都分配一個唯一的整數,這些整數叫做代碼點(Code Points)。

代碼空間

所有的代碼點構成一個代碼空間(Code Space),根據Unicode定義,總共有1,114,112個代碼點,編號從0x0到0x10FFFF。換句話說,如果每個代碼點都能夠代表一個有效字符的話,Unicode標準最多能夠編碼1,114,112,也就是大概110多萬個字符。最新的Unicode標準(7.0)已經給超過11萬個字符分配了代碼點。

代碼平面

Unicode標準把代碼點分成了17個代碼平面(Code Plane),編號爲#0到#16。每個代碼平面包含65,536(2^16)個代碼點(17*65,536=1,114,112)。其中,Plane#0叫做基本多語言平面(Basic Multilingual Plane,BMP),其餘平面叫做補充平面(Supplementary Planes)。Unicode7.0只使用了17個平面中的6個,並且給這6個平面起了名字,如下圖所示:
平面
下面是這些平面的名字和用途:
BMP(Basic Multilingual Plane)大部分常用的字符都坐落在這個平面內,比如ASCII字符,漢字等。
SMP(Supplementary Multilingual Plane)這個平面定義了一些古老的文字,不常用。
SIP(Supplementary Ideographic Plane)這個平面主要是一些BMP中沒有包含漢字。
SSP(Supplementary Special-purpose Plane)這個平面定義了一些非圖形字符。

1. Unicode與ISO 10646

全世界很多個國家都在爲自己的文字編碼,並且互不想通,不同的語言字符編碼值相同卻代表不同的符號(例如:韓文編碼EUC-KR中“한국어”的編碼值正好是漢字編碼GBK中的“茄憊絹”)。因此,同一份文檔,拷貝至不同語言的機器,就可能成了亂碼,於是人們就想:我們能不能定義一個超大的字符集,它可以容納全世界所有的文字字符,再對它們統一進行編碼,讓每一個字符都對應一個不同的編碼值,從而就不會再有亂碼了。

如果說“各個國家都在爲自己文字獨立編碼”是百家爭鳴,那麼“建立世界統一的字符編碼”則是一統江湖,誰都想來做這個武林盟主。早前就有兩個機構試圖來做這個事:
(1) 國際標準化組織(ISO),他們於1984年創建ISO/IEC JTC1/SC2/WG2工作組,試圖制定一份“通用字符集”(Universal Character Set,簡稱UCS),並最終制定了ISO 10646標準。
(2) 統一碼聯盟,他們由Xerox、Apple等軟件製造商於1988年組成,並且開發了Unicode標準(The Unicode Standard,這個前綴Uni很牛逼哦—Unique, Universal, and Uniform)。
1991年前後,兩個項目的參與者都認識到,世界不需要兩個不兼容的字符集。於是,它們開始合併雙方的工作成果,併爲創立一個單一編碼表而協同工作。從Unicode 2.0開始,Unicode採用了與ISO 10646-1相同的字庫和字碼;ISO也承諾,ISO 10646將不會替超出U+10FFFF的UCS-4編碼賦值,以使得兩者保持一致。兩個項目仍都獨立存在,並獨立地公佈各自的標準。不過由於Unicode這一名字比較好記,因而它使用更爲廣泛。

Unicode編碼點分爲17個平面(plane),每個平面包含216(即65536)個碼位(code point)。17個平面的碼位可表示爲從U+xx0000到U+xxFFFF,其中xx表示十六進制值從0016到1016,共計17個平面

2. UTF-32與UCS-4

在Unicode與ISO 10646合併之前,ISO 10646標準爲“通用字符集”(UCS)定義了一種31位的編碼形式(即UCS-4),其編碼固定佔用4個字節,編碼空間爲0x00000000~0x7FFFFFFF(可以編碼20多億個字符)。

UCS-4有20多億個編碼空間,但實際使用範圍並不超過0x10FFFF,並且爲了兼容Unicode標準,ISO也承諾將不會爲超出0x10FFFF的UCS-4編碼賦值。由此UTF-32編碼被提出來了,它的編碼值與UCS-4相同,只不過其編碼空間被限定在了0~0x10FFFF之間。因此也可以說:UTF-32是UCS-4的一個子集

3. UTF-16與UCS-2

除了UCS-4,ISO 10646標準爲“通用字符集”(UCS)定義了一種16位的編碼形式(即UCS-2),其編碼固定佔用2個字節,它包含65536個編碼空間(可以爲全世界最常用的63K字符編碼,爲了兼容Unicode,0xD800-0xDFFF之間的碼位未使用)。例:“漢”的UCS-2編碼爲6C49。

但倆個字節並不足以正真地“一統江湖”(a fixed-width 2-byte encoding could not encode enough characters to be truly universal),於是UTF-16誕生了,與UCS-2一樣,它使用兩個字節爲全世界最常用的63K字符編碼,不同的是,它使用4個字節對不常用的字符進行編碼。UTF-16屬於變長編碼。

前面提到過:Unicode編碼點分爲17個平面(plane),每個平面包含216(即65536)個碼位(code point),而第一個平面稱爲“基本多語言平面”(Basic Multilingual Plane,簡稱BMP),其餘平面稱爲“輔助平面”(Supplementary Planes)。其中“基本多語言平面”(00xFFFF)中0xD8000xDFFF之間的碼位作爲保留,未使用。UCS-2只能編碼“基本多語言平面”中的字符,此時UTF-16與UCS-2的編碼一樣(都直接使用Unicode的碼位作爲編碼值),例:“漢”在Unicode中的碼位爲6C49,而在UTF-16編碼也爲6C49。另外,UTF-16還可以利用保留下來的0xD800-0xDFFF區段的碼位來對“輔助平面”的字符的碼位進行編碼,因此UTF-16可以爲Unicode中所有的字符編碼。

UTF-16中如何對“輔助平面”進行編碼呢?
Unicode的碼位區間爲00x10FFFF,除“基本多語言平面”外,還剩0xFFFFF個碼位(並且其值都大於或等於0x10000)。對於“輔助平面”內的字符來說,如果用它們在Unicode中碼位值減去0x10000,則可以得到一個00xFFFFF的區間(該區間中的任意值都可以用一個20-bits的數字表示)。該數字的前10位(bits)加上0xD800,就得到UTF-16四字節編碼中的前兩個字節;該數字的後10位(bits)加上0xDC00,就得到UTF-16四字節編碼中的後兩個字節。例如:
(這個字念啥?_
上面這個漢字的Unicode碼位值爲2AEAB,減去0x10000得到1AEAB(二進制值爲0001 1010 1110 1010 1011),前10位加上D800得到D86B,後10位加上DC00得到DEAB。於是該字的UTF-16編碼值爲D86BDEAB(該值爲大端表示,小端爲6BD8ABDE)。

4. UTF-8

從前述內容可以看出:無論是UTF-16/32還是UCS-2/4,一個字符都需要多個字節來編碼,這對那些英語國家來說多浪費帶寬啊!(尤其在網速本來就不快的那個年代。。。)由此,UTF-8產生了。在UTF-8編碼中,ASCII碼中的字符還是ASCII碼的值,只需要一個字節表示,其餘的字符需要2字節、3字節或4字節來表示。

UTF-8的編碼規則:
(1) 對於ASCII碼中的符號,使用單字節編碼,其編碼值與ASCII值相同(詳見:U0000.pdf)。其中ASCII值的範圍爲0~0x7F,所有編碼的二進制值中第一位爲0(這個正好可以用來區分單字節編碼和多字節編碼)。
(2) 其它字符用多個字節來編碼(假設用N個字節),多字節編碼需滿足:第一個字節的前N位都爲1,第N+1位爲0,後面N-1 個字節的前兩位都爲10,這N個字節中其餘位全部用來存儲Unicode中的碼位值。

字節數 Unicode UTF-8編碼
1 000000-00007F 0xxxxxxx
2 000080-0007FF 110xxxxx 10xxxxxx
3 000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 010000-10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

5. 總結

(1) 簡單地說:Unicode屬於字符集,不屬於編碼,UTF-8、UTF-16等是針對Unicode字符集的編碼。
(2) UTF-8、UTF-16、UTF-32、UCS-2、UCS-4對比:

對比 UTF-8 UTF-16 UTF-32 UCS-2 UCS-4
編碼空間 0-10FFFF 0-10FFFF 0-10FFFF 0-FFFF 0-7FFFFFFF
最少編碼字節數 1 2 4 2 4
最多編碼字節數 4 4 4 2 4
4 4 4 2 4
是否依賴字節序
發佈了30 篇原創文章 · 獲贊 4 · 訪問量 4437
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章