• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 45  文章 - 129  trackbacks - 0
            <2007年1月>
            31123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910

            專注于C++ P2P STL GP OpenSource等
            Google

            常用鏈接

            留言簿(10)

            隨筆分類

            隨筆檔案

            相冊

            朋友

            • .NET

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            摘要:本文在對各種資料整理后詳細(xì)介紹各種常見編碼的轉(zhuǎn)換算法。

            一、通用字符集(UCS)

            ISO/IEC 10646-1 [ISO-10646]定義了一種多于8比特字節(jié)的字符集,稱作通用字符集(UCS),它包含了世界上大多數(shù)可書寫的字符系統(tǒng)。 已定義了兩種多8比特字節(jié)編碼,對每一個字符采用四個8比特字節(jié)編碼的稱為UCS-4,對每一個字符采用兩個8比特字節(jié)編碼的稱為UCS-2。 它們僅能夠?qū)CS的前64K字符進行編址,超出此范圍的其它部分當(dāng)前還沒有分配編址。

            二、基本多語言面(BMP)

            ISO 10646 定義了一個31位的字符集。 然而,在這巨大的編碼空間中,迄今為止只分配了前65534個碼位 (0x0000 到 0xFFFD)。 這個UCS的16位子集稱為 “基本多語言面 ”(Basic Multilingual Plane, BMP)。

            三、Unicode編碼

            歷史上, 有兩個獨立的, 創(chuàng)立單一字符集的嘗試。 一個是國際標(biāo)準(zhǔn)化組織(ISO)的 ISO 10646 項目; 另一個是由(一開始大多是美國的)多語言軟件制造商組成的協(xié)會組織的 Unicode 項目。幸運的是, 1991年前后, 兩個項目的參與者都認(rèn)識到: 世界不需要兩個不同的單一字符集。它們合并雙方的工作成果,并為創(chuàng)立一個單一編碼表而協(xié)同工作。 兩個項目仍都存在并獨立地公布各自的標(biāo)準(zhǔn), 但 Unicode 協(xié)會和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標(biāo)準(zhǔn)的碼表兼容, 并緊密地共同調(diào)整任何未來的擴展。Unicode 標(biāo)準(zhǔn)額外定義了許多與字符有關(guān)的語義符號學(xué), 一般而言是對于實現(xiàn)高質(zhì)量的印刷出版系統(tǒng)的更好的參考。

            四、UTF-8編碼

            UCS-2和UCS-4編碼很難在許多當(dāng)前的應(yīng)用和協(xié)議中使用,這些應(yīng)用和協(xié)議假定字符為一個8或7比特的字節(jié)。 即使新的可以處理16比特字符的系統(tǒng),卻不能處理UCS-4數(shù)據(jù)。這種情況導(dǎo)致一種稱為UCS轉(zhuǎn)換格式(UTF)的發(fā)展,它每一種有不同的特征。 UTF-8(RFC 2279),使用了8比特字節(jié)的所有位,保持全部US-ASCII取值范圍的性質(zhì):US-ASCII字符用一個8比特字節(jié)編碼,采用通常的US-ASCII值, 因此,在此值下的任何一個8比特位字節(jié)僅僅代表一個US-ASCII字符,而不會為其他字符。它有如下的特性:

            1)UTF-8向UCS-4,UCS-2兩者中任一個進行相互轉(zhuǎn)換比較容易。
            2)多8比特字節(jié)序列的第一個8比特字節(jié)指明了系列中8比特字節(jié)的數(shù)目。
            3)8比特字節(jié)值FE和FF永遠(yuǎn)不會出現(xiàn)。
            4)在8比特字符流中字符邊界從哪里開始較容易發(fā)現(xiàn)。

            UTF-8定義:
            在UTF-8中,字符采用1到6個8比特字節(jié)的序列進行編碼。僅僅一個8比特字節(jié)的一個序列中,字節(jié)的高位為0,其他的7位用于字符值編碼。n (n>1)個8比特字節(jié)的一個序列中,初始的8比特字節(jié)中高n位為1,接著一位為0,此字節(jié)余下的位包含被編碼字符值的位。接著的所有8比特字節(jié)的 最高位為1,接著下一位為0,余下每個字節(jié)6位包含被編碼字符的位。

            下表總結(jié)了這些不同的8比特字節(jié)類型格式。字母x指出此位來自于進行編碼的UCS-4字符值。

             

               UCS-4范圍(16進制)     UTF-8 系列(二進制)
            0000 0000<->0000 007F 0xxxxxxx
            0000 0080<->0000 07FF 110xxxxx 10xxxxxx
            0000 0800<->0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx

            0001 0000<->001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
            0020 0000<->03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
            0400 0000<->7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx

            從UCS-4 到 UTF-8編碼規(guī)則如下:
            1)從字符值和上表第一列中決定需要的8比特字節(jié)數(shù)目。著重指出的是上表中的行是相互排斥的,也就是說,對于一個給定的UCS-4字符,僅僅有一個有效的編碼。
            2)按照上表中第二列每行那樣準(zhǔn)備8比特字節(jié)的高位。
            3)將UCS字符值的位,從低位起填充在標(biāo)記為x地方。從UTF8序列中最后一個字節(jié)填起,然后剩下的字符值依次放到前一個字節(jié)中,如此重復(fù),直到所有標(biāo)記位x的位都進行了填充。

            這里我們僅僅實現(xiàn)Unicode到UTF8的轉(zhuǎn)換,Unicode都是兩個字節(jié),定義為:
            typedef usigned short WCHAR

            // 輸出的UTF8編碼至多是3個字節(jié)。

            int UnicodeToUTF8(WCHAR ucs2, unsigned char *buffer)
            {
                memset(buffer, 
            04);
                
            if ((0x0000 <= ucs2) && (ucs2 <= 0x007f))  // one char of UTF8
                {
                   buffer[
            0= (char)ucs2;
                   
            return 1;
                }
                
            if ((0x0080 <= ucs2) && (ucs2 <= 0x07ff))  // two char of UTF8
                {
                   buffer[
            1= 0x80 | char(ucs2 & 0x003f);
                   buffer[
            0= 0xc0 | char((ucs2 >> 6& 0x001f);
                   
            return 2;
                }
                
            if ((0x0800 <= ucs2) && (ucs2 <= 0xffff))  // three char of UTF8
                {
                   buffer[
            2= 0x80 | char(ucs2 & 0x003f);
                   buffer[
            1= 0x80 | char((ucs2 >> 6& 0x003f);
                   buffer[
            0= 0xe0 | char((ucs2 >> 12& 0x001f);
                   
            return 3;
                }
                
            return 0;
            }  


            理論上,簡單的通過用2個0值的8比特字節(jié)來擴展每個UCS-2字符,則從UCS-2到UTF-8編碼的算法可以從上面得到。然而,從D800到DFFF 間的UCS-2值對(用Unicode說法是代理對),實際上是通過UTF-16來進行UCS-4字符轉(zhuǎn)換,因此需要特別對待:UTF-16轉(zhuǎn)換必須未完 成,先轉(zhuǎn)換到于UCS-4字符,然后按照上面過程進行轉(zhuǎn)換。

            從UTF-8到UCS-4解碼過程如下:
            1)初始化UCS-4字符4個8比特字節(jié)的所有位為0。
            2)根據(jù)序列中8比特字節(jié)數(shù)和上表中第二列(標(biāo)記為x位)來決定哪些位編碼用于字符值。
            3)從編碼序列分配位到UCS-4字符。首先從序列最后一個8比特字節(jié)的最低位開始,接著向左進行,直到所有標(biāo)記為x的位完成。如果UTF-8序列長度不大于3個8比特字節(jié),解碼過程可以直接賦予UCS-2。

            WCHAR UTF8ToUnicode(unsigned char *buffer)
            {
                WCHAR temp 
            = 0;
                
            if (buffer[0< 0x80)                                   // one char of UTF8
                { 
                   temp 
            = buffer[0];
                }
                
            if ((0xc0 <= buffer[0]) && (buffer[0< 0xe0))          // two char of UTF8
                {
                   temp 
            = buffer[0& 0x1f;
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[1& 0x3f);
                }
                
            if ((0xe0 <= buffer[0]) && (buffer[0< 0xf0))          // three char of UTF8
                {
                   temp 
            = buffer[0& 0x0f;
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[1& 0x3f);
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[2& 0x3f);
                }
                
            if ((0x80 <= buffer[0]) && (buffer[0< 0xc0))          // not the first byte of UTF8 character
                   return 0xfeff;                                       // 0xfeff will never appear in usual

                
            return temp;                                            // more than 3-bytes return 0
            }


            注意:上面解碼算法的實際實現(xiàn)應(yīng)該進行安全保護,以便處理解碼無效的系列。例如:實現(xiàn)可能(錯誤)解碼無效的UTF-8系列0xC0 0x80為字符U+0000,它可能導(dǎo)致安全問題或其他問題(比如把0當(dāng)作數(shù)組結(jié)束標(biāo)志)。更詳細(xì)的算法和公式可以在[FSS_UTF], [UNICODE] 或[ISO-10646]附錄R中找到。

            五、UTF-7編碼

            UTF-7:A Mail-Safe Transformation Format of Unicode(RFC1642)。這是一種使用 7 位 ASCII 碼對 Unicode 碼進行轉(zhuǎn)換的編碼。它的設(shè)計目的仍然是為了在只能傳遞 7 為編碼的郵件網(wǎng)關(guān)中傳遞信息。 UTF-7 對英語字母、數(shù)字和常見符號直接顯示,而對其他符號用修正的 Base64 編碼。符號 + 和 - 號控制編碼過程的開始和暫停。所以亂碼中如果夾有英文單詞,并且相伴有 + 號和 - 號,這就有可能是 UTF-7 編碼。

            協(xié)議中定義的轉(zhuǎn)換規(guī)則:
            1)集合D中的Unicode字符可以直接的編碼為ASCII的等值字節(jié)。集合O中的字符可以有有選擇的的直接編碼為ASCII的等值字節(jié),但要記得其中的很多的字符在報頭字段是不合法的,或者不能正確的穿過郵件網(wǎng)關(guān)。
            2)通過在前面加上轉(zhuǎn)換字符"+",任何一個Unicode序列都可以使用集合B(更改過的base64)中的字符編碼。"+"意味著后面的字節(jié)將被作為 更改過的BASE64字母表中的元素解析,直到遇到一個不是字母表中的字符為止。這些字符中會包含控制字符,比如回車和換行;因此,一個Unicode轉(zhuǎn) 換序列總是在一行上結(jié)束。注釋:有兩個特殊的情形:"+-"表示''+'',"+ …… --"表示有一個真正的''-''字符出現(xiàn)了。多數(shù)情況是沒有''-''標(biāo)記結(jié)束。
            3)空格、tab、回車和換行字符可以直接使用ASCII等價字節(jié)表示。

            那么我們就可以定義算法了,我們先定義字符集的相關(guān)數(shù)組:
            typedef unsigned char byte

            // 64 characters for base64 coding
            byte base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  

            // 8 characters are safe just as base64 characters for MAIL gates
            byte safeChars[] = "''(),-.:?";    

            // 4 characters all means space
            byte spaceChars[] = " \t\n\r";    

            注:在編碼處理時候,我們需要對一個字節(jié)判斷屬于哪類字符,以便確定處理規(guī)則,如果簡單的使用范圍比較的方式,效率很低,我們采用哈希表的思路:建立一個256長的數(shù)組,那么對于每一個字節(jié)的值,就可以定義一個類型。判斷時候,對每個字符都直接取數(shù)組的值。

            // mask value defined for indentify the type of a byte
            #define    BASE64        0x01
            #define    SAFE        0x02
            #define    SPACE        0x04
            byte byteType[256];        // hash table used for find the type of a byte
            bool firstTime = true;     // the first time to use the lib, wait for init the table

            // 注:為了解碼base64編碼部分的字符,需要一個哈希表,對一個base64字符都可以直接得到0-64之間的一個數(shù):
            byte base64Value[128];

            這兩個哈希表在使用前要初始化:

            void initUTF7Tables()
            {
                
            byte *s;
                
            if(!firstTime)
                
            return;
                
            // not necessary, but should do it to be robust
                memset(byteType, 0256);
                memset(base64Value, 
            0128);
                
                
            for(s=base64Chars; *s!=''\0''; s++)
                {
                   byteType[
            *s] |= BASE64;
                   base64Value[
            *s] = s - base64Chars; // the offset, it is a 6bits value,0-64
                }
                
                
            for(s=safeChars; *s!=''\0''; s++)
                   byteType[
            *s] |= SAFE;
                   
                
            for(s=spaceChars; *s!=''\0''; s++)
                   byteType[
            *s] |= SPACE; 

                firstTime 
            = false;
            }

            UTF-7編碼轉(zhuǎn)換時候,是與當(dāng)前字符是與狀態(tài)有關(guān)的,也就是說:
            1)正處于Base64編碼狀態(tài)中
            2)正處于直接編碼狀態(tài)中
            3)現(xiàn)在UTF-7的緩沖區(qū)里,當(dāng)前的字符是轉(zhuǎn)換開關(guān)"+"

            所以要定義相關(guān)的字段:

            // the state of current character 
            #define    IN_ASCII    0
            #define    IN_BASE64    1
            #define AFTER_PLUS    2

            在使用規(guī)則2進行編碼時候,需要使用base64的方法,也就需要2個全局的輔助變量:

            int state;                 // state in which  we are working
            int nbits;                 // number of bits in the bit buffer
            unsigned long bitBuffer;   // used for base64 coding

            把一個Unicode字符轉(zhuǎn)化為一個UTF-7序列:返回寫到緩沖區(qū)里的字節(jié)數(shù)目,函數(shù)影響了state,nbits,bitBuffer三個全局變量。 這里先實現(xiàn)了一個簡單的輔助函數(shù),功能是把一個Unicode字符轉(zhuǎn)變后寫到提供的緩沖區(qū)中,返回寫入的字節(jié)個數(shù)。在開始編碼Unicode字符數(shù)組中第 一個字符的時候,state,nbits,bitBuffer三個全局變量需要被初始化:

            state = IN_ASCII;
            nbits 
            = 0;
            bitBuffer 
            = 0;

            int UnicodeToUTF7(WCHAR ucs2, byte *buffer)
            {
                
            byte *head = buffer;
                
            int index;    
                
                
            // is an ASCII and is a byte in char set defined
                if (((ucs2 & 0xff80== 0)) && (byteType[(byte)u2] & (BASE64|SAFE|SPACE))) 
                {    
                   
            byte temp = (byte)ucs2;
                   
                   
            if (state == IN_BASE64) // should switch out from base64 coding here
                   {
                      
            if (nbits > 0)       // if some bits in buffer, then output them
                      {
                         index 
            = (bitBuffer << (6 - nbits)) & 0x3f;
                         
            *s++ = base64[index];
                      }
                      
            if ((byteType[temp] & BASE64) || (temp == ''-''))
                         
            *s++ = ''-'';
                  state 
            = IN_ASCII;
                   }
                   
            *s++ = temp;
                   
                   
            if (temp == ''+'')
                      
            *s++ = ''-'';
                }
                
            else
                {
                   
            if (state == IN_ASCII) 
                   {
                      
            *s++ = ''+'';
                      state 
            = IN_BASE64;          // begins base64 coding here
                      nbits = 0;
                      bitBuffer 
            = 0;
                   }
                   bitBuffer 
            <<= 16;
                   bitBuffer 
            |= ucs2;
                   nbits 
            += 16;
                   
                   
            while(nbits >= 6
                   {
                      nbits 
            -= 6;
                      index 
            = (bitBuffer >> nbits) & 0x3f;   // output the high 6 bits
                      *s++ = base64[index];
                   }
                }
                
            return (s - head);
            }


            說明:對于合法的Unicode字符數(shù)組,可以通過逐個輸入數(shù)組中的字符,連續(xù)調(diào)用上面的函數(shù),得到一個UTF-7字節(jié)序列。需要說明的是:最后一個Unicode字符應(yīng)該是上面三個字節(jié)數(shù)組中某個字符的等值。

            下面,我們實現(xiàn)一個簡單的說明函數(shù),功能是:輸入一個UTF-7字節(jié),可能得到并返回一個合法Unicode字符;也可能不能得到,比如遇到''+''或者因為還沒有完成一個字符的拼裝,這時返回一個標(biāo)志字符0xfeff,這個字符常用來標(biāo)志Unicode編碼。

            注:函數(shù)影響了state,nbits,bitBuffer三個全局變量。在開始處理第一個字節(jié)時候,變量需要被初始化為:

            state = IN_ASCII;
            nbits 
            = 0;
            bitBuffer 
            = 0;

            #define RET0 0xfeff

            WCHAR UTF7ToUnicode(
            byte c)
            {
                
            if(state == IN_ASCII) 
                {
                   
            if (c == ''+''
                   {
                      state 
            = AFTER_PLUS;
                      
            return RET0;
                   } 
                   
            else 
                    
            return (WCHAR)c;
                }
                
            if (state == AFTER_PLUS) 
                {
                   
            if (c == ''-''
                   {
                      
            return (WCHAR)''+'';
                   } 
                   
            else 
                   {
                      state 
            = IN_BASE64;
                      nbits 
            = 0;
                      bitBuffer 
            = 0;  // it is not necessary
                      
            // don''t return yet, continue to the IN_BASE64 mode
                   }
                 }
                 
                
            // state == Base64 
                if (byteType[c] & BASE64) 
                {
                   bitBuffer 
            <<= 6;
                   bitBuffer 
            |= base64Value[c];
                   nbits 
            += 6;
                   
            if (nbits >= 16
                   {
                      nbits 
            -= 16;
                  
            return (WCHAR)((bitBuffer >> nbits) & 0x0000ffff);
                   }
                   
            return RET0;
                }
                
            // encount a byte which is not in base64 character set, switch out of base64 coding
                state = IN_ASCII;
                
            if (c != ''-''
                {
                   
            return (WCHAR)c;
                }
                
            return RET0;
            }


            說明:對于一個UTF-7序列,可以通過連續(xù)輸入字節(jié)并調(diào)用上面的函數(shù),判斷返回值,得到一個Unicode字符數(shù)組。

            六、GB2312編碼中漢字的確定

            最早,表示漢字的區(qū)位碼中,分為94個區(qū),每個區(qū)94個漢字,1-15區(qū)是西文字符,圖形等,16-5為一級漢字,56-87為二級漢字,87區(qū)以上為新 字用。而我們在Windows默認(rèn)的編碼,GB2312(1981年國家頒布的《信息交換用漢字編碼字符集基本集》)國標(biāo)碼,和區(qū)位碼的換算為:

            國標(biāo)碼 = 區(qū)位碼 + 2020H

            而在漢字在計算機內(nèi)表示的時候為保證ASCII碼和漢字編碼的不混淆,又做了一個換算:

            漢字機內(nèi)碼 = 國標(biāo)碼 + 8080H

            所以,真正的在Windows上的GB2312漢字編碼是機內(nèi)碼,從上邊的兩個公式可以得到的就是:

            漢字機內(nèi)碼 = 區(qū)位碼 + a0a0H

            一個漢字的編碼最少要a0a0H,因此我們在CString中辨別漢字的時候可以認(rèn)為:當(dāng)一個字符的編碼大于a0的時候它應(yīng)該是漢字的一個部分。但是也有 特殊的情況的,不是每個漢字的兩個字節(jié)編碼都是大于a0H的,例如‘镕’的編碼是 ‘E946’,后面的部分就不滿足大于a0H的條件。

            七、Windows下多字節(jié)編碼和Unicode的轉(zhuǎn)換

            Windows提供了API函數(shù),可以把Unicode字符數(shù)組轉(zhuǎn)換為GB2312字符串。其中,Unicode數(shù)組在傳入時候最后一個為0,也就是所謂 的null termidated字符串。在函數(shù)內(nèi)部得到要返回字節(jié)串的大小,請求空間,進行真正的轉(zhuǎn)換操作,指針在外部使用后釋放,或者在類中加如其他的操作來處 理,比如析構(gòu)函數(shù)中釋放。返回值為寫到字節(jié)串里數(shù)目。

            	
            int StringEncode::UnicodeToGB2312(char **dest, const WCHAR *src)
            {
                
            char* buffer;
                
            int size = ::WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);  
                
            // null termidated wchar''s buffer
                buffer = new char[size];
                
            int ret = ::WideCharToMultiByte(CP_ACP, NULL, src, -1, buffer, size + 1, NULL, NULL);

                
            if (*dest != 0)
                    delete 
            *dest;
                
            *dest = buffer;

                
            return ret;
            }


            注:其中見到有人在使用的時候,申請緩沖區(qū)空間時候是申請了(zise + 1)個來,最后一個字節(jié)寫''\0'',結(jié)束字符串。但是在我調(diào)試時候發(fā)現(xiàn):系統(tǒng)給的size已經(jīng)包含了一個寫入''\0''的字節(jié),而且最后得到的串 中,''\0''是已經(jīng)被系統(tǒng)API寫入了。(也許我的實驗有錯誤,有待驗證)。把Unicode字符數(shù)組轉(zhuǎn)換為UTF-8和UTF-7的方法類似,只要 是WideCharToMultiByte函數(shù)的第一個表示代碼頁參數(shù)改為CP_UTF7(65000)和CP_UTF8(65001)。

            同樣道理,把多字節(jié)轉(zhuǎn)換為Unicode字符數(shù)組,也有相應(yīng)的函數(shù)。和上面的函數(shù)類似,可以通過先提供一個空緩沖區(qū)而先得到需要的大小,然后開辟空間得到 最后的字符數(shù)組。但是考慮到效率,可以適當(dāng)犧牲一些空間,提供一個足夠大的字符數(shù)組,數(shù)組大小在極端的情況下(全是ASCII)是和字節(jié)數(shù)組大小一樣的。

            int StringEncode::Gb2312ToUnicode(WCHAR **dest, const char *src)
            {
                
            int length = strlen(src);                // null terminated buffer
                WCHAR *buffer = new WCHAR[length + 1];   // WCHAR means unsinged short, 2 bytes
                                                       
            // provide enough buffer size for Unicodes

                
            int ret = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, length, buffer, length);
                buffer[ret] 
            = 0;

                
            if (*dest != 0)
                    delete 
            *dest;
                
            *dest = buffer;

                
            return ret;
            }


            注:刪除以前的緩沖區(qū)時候的操作,其實沒有必要判斷是不是為空,因為刪除空指針是沒有問題的,因為delete內(nèi)部提供了這樣的機制。

            八、URL 解碼

            用IE發(fā)送GET請求的時候,URL是用UTF-8編碼的,當(dāng)對截包數(shù)據(jù)分析時候就需要對數(shù)據(jù)解碼,下面的函數(shù)是一個簡單的實現(xiàn):

            CString CTestUrlDlg::UrlToString(CString url)
            {
                CString  str 
            = "";
                
            int n = url.GetLength();
                url.MakeLower();
                BYTE a, b1, b2;
                
            for (int i=0; i< 3)    // 后面沒有兩個字符了,錯誤
                            return "";
                        b1 
            = charToHex( url.GetAt(i+1) );
                        b1 
            = (b1 << 4& 0xf0;
                        b2 
            = charToHex( url.GetAt(i+2) ) & 0x0f;
                        a 
            = b1 | b2;
                        str 
            += a;
                        i 
            += 2;
                    }
                    
            else
                    {
                        str 
            += url.GetAt(i);
                    }
                }
                
            return str;
                
                }
                
            static WCHAR UTF8ToUnicode(unsigned char *buf, int &t)
            {
                WCHAR temp 
            = 0;
                unsigned 
            char *buffer = buf + t;
                
            if (buffer[0< 0x80)                                   // one char of UTF8
                { 
                   temp 
            = buffer[0];
                   t 
            += 1;
                }
                
            if ((0xc0 <= buffer[0]) && (buffer[0< 0xe0))          // two char of UTF8
                {
                   temp 
            = buffer[0& 0x1f;
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[1& 0x3f);
                   t 
            += 2;
                }
                
            if ((0xe0 <= buffer[0]) && (buffer[0< 0xf0))          // three char of UTF8
                {
                   temp 
            = buffer[0& 0x0f;
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[1& 0x3f);
                   temp 
            = temp << 6;
                   temp 
            = temp | (buffer[2& 0x3f);
                   t 
            += 3;
                }
                
            if ((0x80 <= buffer[0]) && (buffer[0< 0xc0))          // not the first byte of UTF8 character
                   return 0xfeff;                                       // 0xfeff will never appear in usual

                
            return temp;                                            // more than 3-bytes return 0
            }


            static unsigned char charToHex(char c)
            {
                unsigned 
            char d;
                
            if ((c >= ''0''&& (c <= ''9''))
                    d 
            = c - ''0'';
                
            else if ((c >= ''a''&& (c <= ''f''))
                {
                    d 
            = c - ''a'' + 10;
                }
                
            else if ((c >= ''A''&& (c <= ''F''))
                {
                    d 
            = c - ''A'' + 10;
                }
                
            else
                    d 
            = 0;

                
            return d;    
            }


            static void UnicodeToGB2312(const WCHAR unicode, char* buffer)
            {
            //    int size = ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, NULL, 0, NULL, NULL);  

                
            int ret = ::WideCharToMultiByte(CP_ACP, NULL, &unicode, -1, buffer, 3, NULL, NULL);
            }

            CString CTestUrlDlg::Uft8ToGB(CString url)
            {
                CString  str 
            = "";
                
            char buffer[3];
                WCHAR unicode;
                
                unsigned 
            char * p = (unsigned char *)(LPCTSTR)url;
                
            int n = url.GetLength();
                
            int t = 0;
                
            while (t < n)
                {
                    unicode 
            = UTF8ToUnicode(p, t);
                    UnicodeToGB2312(unicode, buffer);
                    buffer[
            2= 0;
                    str 
            += buffer;
                }

                
            return str;
            }


            示例:
            CString str = "/MFC%E8%8B%B1%E6%96%87%E6%89%8B%E5%86%8C.chm";
            CString ret 
            = UrlToString(str);
            ret 
            = Uft8ToGB(ret);   // MFC英文手冊.chm



            九、總結(jié)
            常見算法還有MIME等,由于篇幅限制,并且網(wǎng)上已經(jīng)有很多帖子,在此不再贅述。
            對于本文,由于個人能力有限,難免有疏漏的地方,還望指教,共同進步。
            posted on 2007-07-24 12:43 CPP&&設(shè)計模式小屋 閱讀(3048) 評論(7)  編輯 收藏 引用 所屬分類: 讀書筆記

            FeedBack:
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-07-24 13:15 go
            good..  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-07-24 13:28 CPP&&設(shè)計模式小屋
            我也覺得總結(jié)的不錯 和大家分享一下。  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-07-24 15:55 pass86
            不錯不錯,支持。  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-07-26 19:49 黃大仙
            正需要這方面的資料  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-08-06 19:51 ouyang2008
            i need too ,3ks.  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-09-09 11:19 vernon
            好文章  回復(fù)  更多評論
              
            # re: 常用編碼詳解(轉(zhuǎn)自VCKBASE)作者:李靜南 2007-09-14 08:22 螞蟻終結(jié)者
            不錯,先收藏了  回復(fù)  更多評論
              
            久久久久亚洲AV片无码下载蜜桃| 久久精品国产第一区二区三区| 久久er国产精品免费观看2| 久久无码国产专区精品| 人妻无码精品久久亚瑟影视| 精品多毛少妇人妻AV免费久久| 色成年激情久久综合| 国产韩国精品一区二区三区久久| 男女久久久国产一区二区三区| 精品久久久中文字幕人妻| 久久天天躁夜夜躁狠狠躁2022| 香蕉久久久久久狠狠色| 久久综合鬼色88久久精品综合自在自线噜噜| 久久伊人亚洲AV无码网站| 亚洲欧洲精品成人久久曰影片| 色综合合久久天天给综看| 久久只这里是精品66| 一本一道久久综合狠狠老| 久久久无码精品亚洲日韩按摩| 国产成人精品久久免费动漫| 一本一道久久精品综合| 丁香五月综合久久激情| 久久久受www免费人成| 亚洲精品综合久久| 人妻精品久久久久中文字幕69| 精品久久久久中文字幕日本| 久久久精品免费国产四虎| 国产一区二区精品久久凹凸| 性做久久久久久免费观看| 精品久久久一二三区| 99久久精品国产高清一区二区 | 久久人人爽人人爽人人AV| 久久久久亚洲AV无码专区体验| 精品久久久久久中文字幕| 久久久久亚洲AV成人网人人网站 | 久久久久亚洲AV成人网人人软件 | 亚洲中文字幕无码久久2017 | 国内精品久久久久久中文字幕| 无码人妻少妇久久中文字幕| 欧洲精品久久久av无码电影| 国产AV影片久久久久久|