Unicode的實作方式不同于編碼方式。一個字元的Unicode編碼是确定的,但是在實際存儲和傳輸過程中,由于不同系統平台的設計不一定一緻,以及出于節省空間的目的,對Unicode編碼的實作方式有所不同。Unicode的實作方式稱為Unicode轉換格式(UnicodeTransformation Format,簡稱為UTF)。
對Unicode編碼的主要有UTF-16BE、UTF-16LE、UTF-8、UTF-7以及UTF-32等實作方式,目前常用的實作方式是UTF-16LE、UTF-16BE和UTF-8。
UTF-16
UTF-16是用16bit編碼來表達Unicode,這樣表達範圍是216(即65536),也就是UTF-16的代碼單元(Code Unit)為16bits。如果表達BMP内的字元,用一個UTF-16的CodeUnit就可表達,對于輔助平面内的字元,UTF-16有巧妙的設計。
落在BMP内,從U+D800到U+DFFF之間的Code Point區段是永久保留不映射到字元, UTF-16利用這保留下來的0xD800-0xDFFF區段的CodePoint來對輔助平面内的字元的Code Point進行編碼。
對U+0000.. U+D7FF以及U+E000.. U+FFFF的編碼
UTF-16與UCS-2對這個範圍内的CodePoint進行編碼,采用單個16bit長的CodeUnit,數值等價于對應的Code Point。BMP中的這些Code Point是僅有的可以被UCS-2表示的Code Point。
對U+10000.. U+10FFFF的編碼
輔助平面(Supplementary Planes)中的CodePoint,在UTF-16中被編碼為一對16bit長的Code Unit(即32bit,4Bytes),稱作代理對(surrogatepair)。
具體方法是:
Code Point減去0x10000, 得到的值是長度為20bit(0..0xFFFFF);
步驟1得到數值的高位的10比特的值(值範圍為0..0x3FF)被加上0xD800得到第一個Code Unit或稱作高位代理(high surrogate)或前導代理(lead surrogate)。取值範圍是0xD800..0xDBFF。
步驟1得到數值的低位的10比特的值(值範圍為0..0x3FF)被加上0xDC00得到第二個Code Unit或稱作低位代理(low surrogate)或後尾代理(trail surrogate)。取值範圍是0xDC00..0xDFFF。
這樣,這個範圍内的字元就被編碼成了一個代理對[leadsurrogate,trail surrogate]:兩個16bits的Code Unit,取值範圍分别是0xD800..0xDBFF和0xDC00..0xDFFF。而BMP中得到的Code Unit的範圍是0x0000..0xFFFF(0xD800..0xDFFF是保留的,不包含其中),是以這三個區段是互相不重疊的,在解碼時很容易實 現。
UTF-16解碼
hi \ lo
DC00
DC01
…
DFFF
D800
10000
10001
…
103FF
D801
10400
10401
…
107FF
⋮
⋮
⋮
⋱
⋮
DBFF
10FC00
10FC01
…
10FFFF
下面以對U+64321的UTF-16編碼為例,看一下對于輔助平面内的字元是如何編碼的:
V = 0x64321
Vx = V - 0x10000
= 0x54321
= 01010100 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
以下是據此而寫的c++加碼與解碼的函數:
//unicode BMP之外字元 轉換成UTF-16 加碼函數
//DWORD v 為字元的UNICODE編碼 編碼值大于0XFFFF
//WORD & w1 為轉換成UTF-16後的 低位代理對
//WORD & w2 為轉換成UTF-16後的 高位代理對
void EnCode(DWORD v,WORD &w1,WORD &w2)
{
DWORD vx=v-0x10000;
WORD vh=(vx&0xFFC00)>>10;
WORD vl=vx&0x03FF;
w1=0xD800;
w2=0xDC00;
w1=w1|vh;
w2=w2|vl;
}
// UTF-16 轉換成unicode編碼的 解碼函數
//DWORD v 為解碼後的字元的UNICODE編碼 編碼值大于0XFFFF
//WORD & w1 UTF-16的 低位代理對
//WORD & w2 UTF-16的 高位代理對
void DeCode(DWORD &w, WORD &w1, WORD &w2)
{
w1=w1&0x3FF;
w2=w2&0x3FF;
w=w1<<10;
w=w|w2;
w+=0x10000;
}
應用舉例:
(1)加碼
WCHAR str[3]; //表示一個字元
memset(str,0,3*sizeof(WCHAR));
dw=0x64321; //該字元的unicode編碼位于BMP之外
WORD w1,w2;
EnCode(dw,w1,w2);
str[0]=w1;
str[1]=w2;
str[3]=0;
(2)解碼
DWORD dw=0;
WORD w1,w2;
w1=str[0];
w2=str[1]; //w2!=0 否則即為BMP之内的碼
DeCode(dw,w1,w2); //dw 為UTF-16 所對應的unicode碼值
參考資料:
http://blog.csdn.net/thl789/article/details/7506133
————————————————
版權聲明:本文為CSDN部落客「清水迎朝陽」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/shuilan0066/article/details/7865715