UTF-16編碼法


作者:Владимир Лесной

Lastest update : 2014/11/13


本篇說明中文語言方程當中,CLF數學碼與UTF-16編碼的混和使用狀況。

UTF-16是一個16位元的Unicode表示法,由於定義區的衝突,CLF數學碼最終是採用UTF-16作為主要處理Unicode的方式。

UTF-16使用U+D800到U+DFFF作為代理對(surrogate pair),Unicode當中U+D800-U+DFFF實際上 是不對應到任何文字空間上面的。

Unicode定義區開始位置
Unicode定義區結束位置 說明
U+0000
U+D7FF
兩位元組。
U+D800
U+DFFF
四位元組。
U+E000
U+FFFF
兩位元組。

大部分軟體宣稱對UTF-8的實作,實際上都是UCS-2的實作規則,因此無法真的處理好U+D800-U+DFFF的區域。

由於使用16位元的資料封包,UTF-16實際有小尾序(Little Endian, LE)及大尾序(Big Endian, BE)的問題,實際編碼上,又再被分隔成UTF-16LE及UTF-16BE兩種。


U+D800-U+DFFF區域的處理


UTF-16的處理方式,使用前置代理(lead surrogates)及後尾代理(trail surrogates)的方式。

作用
位置
編碼區開始位置
編碼區結尾位置
前置代理 高位代理
D800
DBFF
後尾代理 低位代理
DC00
DFFF

這含意即為處於U+010000-U+10FFFF區域的Unicode編碼,在UTF-16的表示方式當中,前面兩個位元組必然處於 U+D800-U+DBFF區間,後面兩個位元組必然處於U+DC00-U+DFFF區間。

LFE碼(Language Formula Encoding,語言方程碼)與UTF-16編碼基本上可以相容,因此,LF+D8000000-LF+DFFFFFFF 之間,實際表達的即為Unicode當中的UTF-16代理碼位置。

UTF-16解碼方式



DC00
DC01

DFFF
D800
00010000
00010001
000103FF
D801
00010400
00010401
000107FF


DBFF
0010FC00
0010FC01
0010FFFF

Unicode定義區當中的0x00010000-0x0010FFFF區域,減去0x00010000以後得到 0x00000000-0x000FFFFF的值。

原始Unicode值
減去0x00010000以後的值
0x00010000 0x00000000
0x0010FFFF 0x000FFFFF

0x00000000-0x000FFFFF是一組20位元的值。

位置
區域
代理碼
計算方式
高位代理
0x000FFC00
D800
D800 + ( UTF-16 >> 10 )
低位代理 0x000003FF
DC00
DC00 + ( UTF-16 & 0x03FF )

語言方程碼與UTF-16之間的變換:

語言方程碼 3
2
1
0
UTF-16 高位代理 低位代理

因此,實際上LFE只使用了的0xD80000000-0xDBFFFFFF區域來表達UTF-16的編 碼,0xDC000000-0xDFFFFFFF區域是沒有用到的。

轉換到Unicode定義區


LFE針對Unicode的處理,實際上保留了0x00000000-0x001FFFFF區間來處理,因此,如果我們轉換到了LFE編碼空間的 時候,UTF-16需要變換到Unicode區域,可以使用下列計算是來變換:

uint32_t highSurrogate = LFE >> 16          ;
uint32_t lowSurrogate  = LFE & 0x0000FFFFul ;
uint32_t lfe                                ;

highSurrogate -= 0xD800         ;
lowSurrogate  -= 0xDC00         ;
lfe            = highSurrogate  ;
lfe          <<= 10             ;
lfe           |= lowSurrogate   ;
lfe           += 0x10000        ;

轉換到UTF-16定義區


如果我們的LFE編碼位處於Unicode定義區,而我們需要轉換到UTF-16定義區,可以使用下列計算是來變換:

uint32_t highSurrogate ;
uint32_t lowSurrogate  ;
uint32_t lfe           ;

lfe            = LFE - 0x10000 ;
lowSurrogate   = lfe & 0x03FF  ;
lowSurrogate  |= 0xDC00        ;
highSurrogate  = lfe >> 10     ;
highSurrogate |= 0xD800        ;
lfe            = highSurrogate ;
lfe          <<= 16            ;
lfe           |= lowSurrogate  ;


實際的軟體處理上,採用UTF-16的處理方式,才不致於發生嚴重的衝碼問題。