utf-16

UTF-16描述[編輯]

Unicode的編碼空間從U+0000到U+10FFFF,共有1,112,064個碼位(code point)可用來映射字符. Unicode的編碼空間可以劃分爲17個平面(plane),每個平面包含216(65,536)個碼位。17個平面的碼位可表示爲從U+xx0000到U+xxFFFF,其中xx表示十六進制值從0016到1016,共計17個平面。第一個平面稱爲基本多語言平面(Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)。其他平面稱爲輔助平面(Supplementary Planes)。基本多語言平面內,從U+D800到U+DFFF之間的碼位區段是永久保留不映射到Unicode字符。UTF-16就利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字符的碼位進行編碼。

從U+0000至U+D7FF以及從U+E000至U+FFFF的碼位[編輯]

第一個Unicode平面(碼位從U+0000至U+FFFF)包含了最常用的字符。該平面被稱爲基本多語言平面,縮寫爲BMP(Basic Multilingual Plane, BMP)。UTF-16與UCS-2編碼這個範圍內的碼位爲16比特長的單個碼元,數值等價於對應的碼位. BMP中的這些碼位是僅有的可以在UCS-2中表示的碼位.

從U+10000到U+10FFFF的碼位[編輯]

輔助平面(Supplementary Planes)中的碼位,在UTF-16中被編碼爲一對16比特長的碼元(即32bit,4Bytes),稱作代理對(surrogate pair),具體方法是:

UTF-16解碼
lead \ trail DC00 DC01    …    DFFF
D800 10000 10001 103FF
D801 10400 10401 107FF
  ⋮
DBFF 10FC00 10FC01 10FFFF
  • 碼位減去0x10000,得到的值的範圍爲20比特長的0..0xFFFFF.
  • 高位的10比特的值(值的範圍爲0..0x3FF)被加上0xD800得到第一個碼元或稱作高位代理(high surrogate),值的範圍是0xD800..0xDBFF.由於高位代理比低位代理的值要小,所以爲了避免混淆使用,Unicode標準現在稱高位代理爲前導代理(lead surrogates).
  • 低位的10比特的值(值的範圍也是0..0x3FF)被加上0xDC00得到第二個碼元或稱作低位代理(low surrogate),現在值的範圍是0xDC00..0xDFFF.由於低位代理比高位代理的值要大,所以爲了避免混淆使用,Unicode標準現在稱低位代理爲後尾代理(trail surrogates).

上述算法可理解爲:輔助平面中的碼位從U+10000到U+10FFFF,共計FFFFF個,即220=1,048,576個,需要20位的空間來表示。如果用兩個16位長的整數組成的序列來表示,第一個整數(稱爲前導代理)要容納上述20位空間的前10位,第二個整數(稱爲後尾代理)容納容納上述20位空間的後10位。還要能根據16位整數的值直接判明屬於前導整數代理的值的範圍(210=1024),還是後尾整數代理的值的範圍(也是210=1024)。因此,需要在基本多語言平面中保留不對應於Unicode字符的2048個碼位,就足以容納前導代理與後尾代理所需要的編碼空間。這對於基本多語言平面總計65536個碼位來說,僅佔3.125%.

由於前導代理、後尾代理、BMP中的有效字符的碼位,三者互不重疊,搜索是簡單的:一個字符編碼的一部分不可能與另一個字符編碼的不同部分相重疊。這意味着UTF-16是自同步(self-synchronizing):可以通過僅檢查一個碼元就可以判定給定字符的下一個字符的起始碼元. UTF-8也有類似優點,但許多早期的編碼模式就不是這樣,必須從頭開始分析文本才能確定不同字符的碼元的邊界.

由於最常有的字符都在基本多文種平面中,許多軟件的處理代理對的部分往往得不到充分的測試。這導致了一些長期的bug與潛在安全漏洞,甚至在廣爲流行得到良好評價的應用軟件[1].

從U+D800到U+DFFF的碼位[編輯]

Unicode標準規定U+D800..U+DFFF的值不對應於任何字符.

但是在使用UCS-2的時代,U+D800..U+DFFF內的值被佔用,用於某些字符的映射。但只要不構成代理對,許多UTF-16編碼解碼還是能把這些不符合Unicode標準的字符映射正確的辨識、轉換成合規的碼元[2].按照Unicode標準,這種碼元串行本來應算作編碼錯誤.

示例:UTF-16編碼程序[編輯]

假設要將U+64321 (16進位)轉成UTF-16編碼.因爲它超過U+FFFF,所以他必須編譯成32位(4個byte)的格式,如下所示:11

V = 0x64321
Vx = V - 0x10000
= 0x54321
= 0101 0100 0011 0010 0001

Vh = 01 0101 0000 // Vx的高位部份的10 bits
Vl = 11 0010 0001 // Vx的低位部份的10 bits
w1 = 0xD800 //結果的前16位元初始值
w2 = 0xDC00 //結果的後16位元初始值

w1 = w1 | Vh
= 1101 1000 0000 0000
   |        01 0101 0000
= 1101 1001 0101 0000
= 0xD950

w2 = w2 | Vl
= 1101 1100 0000 0000
   |        11 0010 0001
= 1101 1111 0010 0001
= 0xDF21

所以這個字U+64321最後正確的UTF-16編碼應該是:

0xD950 0xDF21

而在小尾序中最後的編碼應該是:

0x50D9 0x21DF

因爲這個字超過U+FFFF所以無法用UCS-2的格式編碼

16進制編碼範圍 UTF-16表示方法(二進制) 10進制碼範圍 字節數量
U+0000---U+FFFF xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy 0-65535 2
U+10000---U+10FFFF 110110yyyyyyyyyy 110111xxxxxxxxxx 65536-1114111 4

UTF-16比起UTF-8,好處在於大部分字符都以固定長度的字節(2字節)存儲,但UTF-16卻無法兼容於ASCII編碼。

UTF-16的編碼模式[編輯]

UTF-16的大尾序和小尾序存儲形式都在用。一般來說,以Macintosh製作或存儲的文字使用大尾序格式,以MicrosoftLinux製作或存儲的文字使用小尾序格式。

爲了弄清楚UTF-16文件的大小尾序,在UTF-16文件的開首,都會放置一個U+FEFF字符作爲Byte Order Mark(UTF-16LE以FF FE代表,UTF-16BE以FE FF代表),以顯示這個文本文件是以UTF-16編碼,其中U+FEFF字符在UNICODE中代表的意義是ZERO WIDTH NO-BREAK SPACE,顧名思義,它是個沒有寬度也沒有斷字的空白。

以下的例子有四個字符:“朱”(U+6731)、半角逗號(U+002C)、“聿”(U+807F)、“

發佈了6 篇原創文章 · 獲贊 0 · 訪問量 8434
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章