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 = 0x64321Vx = V - 0x10000 = 0x54321 = 01010100 0011 0010 0001 Vh = 01 0101 0000 // Vx 的高位部份的 10 bitsVl = 11 0010 0001 // Vx 的低位部份的 10 bitsw1 = 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