天天看點

C++實作unicode碼轉換成UTF-16的加碼和解碼函數

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

繼續閱讀