日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

常用编码详解

發(fā)布時(shí)間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常用编码详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文在對各種資料整理后詳細(xì)介紹各種常見編碼的轉(zhuǎn)換算法。 一、通用字符集(UCS) ISO/IEC 10646-1 [ISO-10646]定義了一種多于8比特字節(jié)的字符集,稱作通用字符集(UCS),它包含了世界上大多數(shù)可書寫的字符系統(tǒng)。已定義了兩種多8比特字節(jié)編碼,對每一個(gè)字符采用四個(gè)8比特字節(jié)編碼的稱為UCS-4,對每一個(gè)字符采用兩個(gè)8比特字節(jié)編碼的稱為UCS-2。它們僅能夠?qū)CS的前64K字符進(jìn)行編址,超出此范圍的其它部分當(dāng)前還沒有分配編址。 二、基本多語言面(BMP) ISO 10646 定義了一個(gè)31位的字符集。 然而,在這巨大的編碼空間中,迄今為止只分配了前65534個(gè)碼位 (0x0000 到 0xFFFD)。 這個(gè)UCS的16位子集稱為 “基本多語言面 ”(Basic Multilingual Plane, BMP)。 三、Unicode編碼 歷史上, 有兩個(gè)獨(dú)立的, 創(chuàng)立單一字符集的嘗試。 一個(gè)是國際標(biāo)準(zhǔn)化組織(ISO)的 ISO 10646 項(xiàng)目; 另一個(gè)是由(一開始大多是美國的)多語言軟件制造商組成的協(xié)會組織的 Unicode 項(xiàng)目。幸運(yùn)的是, 1991年前后, 兩個(gè)項(xiàng)目的參與者都認(rèn)識到: 世界不需要兩個(gè)不同的單一字符集。它們合并雙方的工作成果,并為創(chuàng)立一個(gè)單一編碼表而協(xié)同工作。 兩個(gè)項(xiàng)目仍都存在并獨(dú)立地公布各自的標(biāo)準(zhǔn), 但 Unicode 協(xié)會和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標(biāo)準(zhǔn)的碼表兼容, 并緊密地共同調(diào)整任何未來的擴(kuò)展。Unicode 標(biāo)準(zhǔn)額外定義了許多與字符有關(guān)的語義符號學(xué), 一般而言是對于實(shí)現(xiàn)高質(zhì)量的印刷出版系統(tǒng)的更好的參考。 四、UTF-8編碼 UCS-2和UCS-4編碼很難在許多當(dāng)前的應(yīng)用和協(xié)議中使用,這些應(yīng)用和協(xié)議假定字符為一個(gè)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字符用一個(gè)8比特字節(jié)編碼,采用通常的US-ASCII值,因此,在此值下的任何一個(gè)8比特位字節(jié)僅僅代表一個(gè)US-ASCII字符,而不會為其他字符。它有如下的特性: 1)UTF-8向UCS-4,UCS-2兩者中任一個(gè)進(jìn)行相互轉(zhuǎn)換比較容易。 2)多8比特字節(jié)序列的第一個(gè)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個(gè)8比特字節(jié)的序列進(jìn)行編碼。僅僅一個(gè)8比特字節(jié)的一個(gè)序列中,字節(jié)的高位為0,其他的7位用于字符值編碼。n(n>1)個(gè)8比特字節(jié)的一個(gè)序列中,初始的8比特字節(jié)中高n位為1,接著一位為0,此字節(jié)余下的位包含被編碼字符值的位。接著的所有8比特字節(jié)的最高位為1,接著下一位為0,余下每個(gè)字節(jié)6位包含被編碼字符的位。 下表總結(jié)了這些不同的8比特字節(jié)類型格式。字母x指出此位來自于進(jìn)行編碼的UCS-4字符值。 ? ?UCS-4范圍(16進(jìn)制)? ???UTF-8 系列(二進(jìn)制) ? ?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ù)目。著重指出的是上表中的行是相互排斥的,也就是說,對于一個(gè)給定的UCS-4字符,僅僅有一個(gè)有效的編碼。 2)按照上表中第二列每行那樣準(zhǔn)備8比特字節(jié)的高位。 3)將UCS字符值的位,從低位起填充在標(biāo)記為x地方。從UTF8序列中最后一個(gè)字節(jié)填起,然后剩下的字符值依次放到前一個(gè)字節(jié)中,如此重復(fù),直到所有標(biāo)記位x的位都進(jìn)行了填充。 這里我們僅僅實(shí)現(xiàn)Unicode到UTF8的轉(zhuǎn)換,Unicode都是兩個(gè)字節(jié),定義為:
  • typedef usigned short WCHAR
  • // 輸出的UTF8編碼至多是3個(gè)字節(jié)。
  • int UnicodeToUTF8(WCHAR ucs2, unsigned char *buffer)
  • {
  • ? ? memset(buffer, 0, 4);
  • ? ? 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;
  • }??
  • 復(fù)制代碼 理論上,簡單的通過用2個(gè)0值的8比特字節(jié)來擴(kuò)展每個(gè)UCS-2字符,則從UCS-2到UTF-8編碼的算法可以從上面得到。然而,從D800到DFFF間的UCS-2值對(用Unicode說法是代理對),實(shí)際上是通過UTF-16來進(jìn)行UCS-4字符轉(zhuǎn)換,因此需要特別對待:UTF-16轉(zhuǎn)換必須未完成,先轉(zhuǎn)換到于UCS-4字符,然后按照上面過程進(jìn)行轉(zhuǎn)換。 從UTF-8到UCS-4解碼過程如下: 1)初始化UCS-4字符4個(gè)8比特字節(jié)的所有位為0。 2)根據(jù)序列中8比特字節(jié)數(shù)和上表中第二列(標(biāo)記為x位)來決定哪些位編碼用于字符值。 3)從編碼序列分配位到UCS-4字符。首先從序列最后一個(gè)8比特字節(jié)的最低位開始,接著向左進(jìn)行,直到所有標(biāo)記為x的位完成。如果UTF-8序列長度不大于3個(gè)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
  • }
  • 復(fù)制代碼 注意:上面解碼算法的實(shí)際實(shí)現(xiàn)應(yīng)該進(jìn)行安全保護(hù),以便處理解碼無效的系列。例如:實(shí)現(xiàn)可能(錯(cuò)誤)解碼無效的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 碼進(jìn)行轉(zhuǎn)換的編碼。它的設(shè)計(jì)目的仍然是為了在只能傳遞 7 為編碼的郵件網(wǎng)關(guān)中傳遞信息。 UTF-7 對英語字母、數(shù)字和常見符號直接顯示,而對其他符號用修正的 Base64 編碼。符號 + 和 - 號控制編碼過程的開始和暫停。所以亂碼中如果夾有英文單詞,并且相伴有 + 號和 - 號,這就有可能是 UTF-7 編碼。 協(xié)議中定義的轉(zhuǎn)換規(guī)則: 1)集合D中的Unicode字符可以直接的編碼為ASCII的等值字節(jié)。集合O中的字符可以有有選擇的的直接編碼為ASCII的等值字節(jié),但要記得其中的很多的字符在報(bào)頭字段是不合法的,或者不能正確的穿過郵件網(wǎng)關(guān)。 2)通過在前面加上轉(zhuǎn)換字符"+",任何一個(gè)Unicode序列都可以使用集合B(更改過的base64)中的字符編碼。"+"意味著后面的字節(jié)將被作為更改過的BASE64字母表中的元素解析,直到遇到一個(gè)不是字母表中的字符為止。這些字符中會包含控制字符,比如回車和換行;因此,一個(gè)Unicode轉(zhuǎn)換序列總是在一行上結(jié)束。注釋:有兩個(gè)特殊的情形:"+-"表示''+'',"+ …… --"表示有一個(gè)真正的''-''字符出現(xiàn)了。多數(shù)情況是沒有''-''標(biāo)記結(jié)束。 3)空格、tab、回車和換行字符可以直接使用ASCII等價(jià)字節(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";? ?
  • 復(fù)制代碼 注:在編碼處理時(shí)候,我們需要對一個(gè)字節(jié)判斷屬于哪類字符,以便確定處理規(guī)則,如果簡單的使用范圍比較的方式,效率很低,我們采用哈希表的思路:建立一個(gè)256長的數(shù)組,那么對于每一個(gè)字節(jié)的值,就可以定義一個(gè)類型。判斷時(shí)候,對每個(gè)字符都直接取數(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編碼部分的字符,需要一個(gè)哈希表,對一個(gè)base64字符都可以直接得到0-64之間的一個(gè)數(shù):
  • byte base64Value[128];
  • 復(fù)制代碼 這兩個(gè)哈希表在使用前要初始化:
  • void initUTF7Tables()
  • {
  • ? ? byte *s;
  • ? ? if(!firstTime)
  • ? ? ? ? return;
  • ? ? // not necessary, but should do it to be robust
  • ? ? memset(byteType, 0, 256);
  • ? ? memset(base64Value, 0, 128);
  • ? ?
  • ? ? 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;
  • }
  • 復(fù)制代碼 UTF-7編碼轉(zhuǎn)換時(shí)候,是與當(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
  • 復(fù)制代碼 在使用規(guī)則2進(jìn)行編碼時(shí)候,需要使用base64的方法,也就需要2個(gè)全局的輔助變量:
  • int state;? ?? ?? ?? ?? ???// state in which??we are working
  • int nbits;? ?? ?? ?? ?? ???// number of bits in the bit buffer
  • unsigned long bitBuffer;? ?// used for base64 coding
  • 復(fù)制代碼 把一個(gè)Unicode字符轉(zhuǎn)化為一個(gè)UTF-7序列:返回寫到緩沖區(qū)里的字節(jié)數(shù)目,函數(shù)影響了state,nbits,bitBuffer三個(gè)全局變量。這里先實(shí)現(xiàn)了一個(gè)簡單的輔助函數(shù),功能是把一個(gè)Unicode字符轉(zhuǎn)變后寫到提供的緩沖區(qū)中,返回寫入的字節(jié)個(gè)數(shù)。在開始編碼Unicode字符數(shù)組中第一個(gè)字符的時(shí)候,state,nbits,bitBuffer三個(gè)全局變量需要被初始化:
  • 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);
  • }
  • 復(fù)制代碼 說明:對于合法的Unicode字符數(shù)組,可以通過逐個(gè)輸入數(shù)組中的字符,連續(xù)調(diào)用上面的函數(shù),得到一個(gè)UTF-7字節(jié)序列。需要說明的是:最后一個(gè)Unicode字符應(yīng)該是上面三個(gè)字節(jié)數(shù)組中某個(gè)字符的等值。 下面,我們實(shí)現(xiàn)一個(gè)簡單的說明函數(shù),功能是:輸入一個(gè)UTF-7字節(jié),可能得到并返回一個(gè)合法Unicode字符;也可能不能得到,比如遇到''+''或者因?yàn)檫€沒有完成一個(gè)字符的拼裝,這時(shí)返回一個(gè)標(biāo)志字符0xfeff,這個(gè)字符常用來標(biāo)志Unicode編碼。 注:函數(shù)影響了state,nbits,bitBuffer三個(gè)全局變量。在開始處理第一個(gè)字節(jié)時(shí)候,變量需要被初始化為:
  • 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;
  • }
  • 復(fù)制代碼 說明:對于一個(gè)UTF-7序列,可以通過連續(xù)輸入字節(jié)并調(diào)用上面的函數(shù),判斷返回值,得到一個(gè)Unicode字符數(shù)組。 六、GB2312編碼中漢字的確定 最早,表示漢字的區(qū)位碼中,分為94個(gè)區(qū),每個(gè)區(qū)94個(gè)漢字,1-15區(qū)是西文字符,圖形等,16-5為一級漢字,56-87為二級漢字,87區(qū)以上為新字用。而我們在Windows默認(rèn)的編碼,GB2312(1981年國家頒布的《信息交換用漢字編碼字符集基本集》)國標(biāo)碼,和區(qū)位碼的換算為: 國標(biāo)碼 = 區(qū)位碼 + 2020H 而在漢字在計(jì)算機(jī)內(nèi)表示的時(shí)候?yàn)楸WCASCII碼和漢字編碼的不混淆,又做了一個(gè)換算: 漢字機(jī)內(nèi)碼 = 國標(biāo)碼 + 8080H 所以,真正的在Windows上的GB2312漢字編碼是機(jī)內(nèi)碼,從上邊的兩個(gè)公式可以得到的就是: 漢字機(jī)內(nèi)碼 = 區(qū)位碼 + a0a0H 一個(gè)漢字的編碼最少要a0a0H,因此我們在CString中辨別漢字的時(shí)候可以認(rèn)為:當(dāng)一個(gè)字符的編碼大于a0的時(shí)候它應(yīng)該是漢字的一個(gè)部分。但是也有特殊的情況的,不是每個(gè)漢字的兩個(gè)字節(jié)編碼都是大于a0H的,例如‘镕’的編碼是 ‘E946’,后面的部分就不滿足大于a0H的條件。 七、Windows下多字節(jié)編碼和Unicode的轉(zhuǎn)換 Windows提供了API函數(shù),可以把Unicode字符數(shù)組轉(zhuǎn)換為GB2312字符串。其中,Unicode數(shù)組在傳入時(shí)候最后一個(gè)為0,也就是所謂的null termidated字符串。在函數(shù)內(nèi)部得到要返回字節(jié)串的大小,請求空間,進(jìn)行真正的轉(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;
  • }
  • 復(fù)制代碼 注:其中見到有人在使用的時(shí)候,申請緩沖區(qū)空間時(shí)候是申請了(zise + 1)個(gè)來,最后一個(gè)字節(jié)寫''\0'',結(jié)束字符串。但是在我調(diào)試時(shí)候發(fā)現(xiàn):系統(tǒng)給的size已經(jīng)包含了一個(gè)寫入''\0''的字節(jié),而且最后得到的串中,''\0''是已經(jīng)被系統(tǒng)API寫入了。(也許我的實(shí)驗(yàn)有錯(cuò)誤,有待驗(yàn)證)。把Unicode字符數(shù)組轉(zhuǎn)換為UTF-8和UTF-7的方法類似,只要是WideCharToMultiByte函數(shù)的第一個(gè)表示代碼頁參數(shù)改為CP_UTF7(65000)和CP_UTF8(65001)。 同樣道理,把多字節(jié)轉(zhuǎn)換為Unicode字符數(shù)組,也有相應(yīng)的函數(shù)。和上面的函數(shù)類似,可以通過先提供一個(gè)空緩沖區(qū)而先得到需要的大小,然后開辟空間得到最后的字符數(shù)組。但是考慮到效率,可以適當(dāng)犧牲一些空間,提供一個(gè)足夠大的字符數(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;
  • }
  • 復(fù)制代碼 注:刪除以前的緩沖區(qū)時(shí)候的操作,其實(shí)沒有必要判斷是不是為空,因?yàn)閯h除空指針是沒有問題的,因?yàn)閐elete內(nèi)部提供了這樣的機(jī)制。 八、URL 解碼
  • 用IE發(fā)送GET請求的時(shí)候,URL是用UTF-8編碼的,當(dāng)對截包數(shù)據(jù)分析時(shí)候就需要對數(shù)據(jù)解碼,下面的函數(shù)是一個(gè)簡單的實(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<n; i++)
  • ? ? ? ? {
  • ? ? ? ? ? ? ? ? if (url.GetAt(i) == ''%'')
  • ? ? ? ? ? ? ? ? {
  • ? ? ? ? ? ? ? ? ? ? ? ? if ((n - i) < 3)? ? // 后面沒有兩個(gè)字符了,錯(cuò)誤
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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;
  • }
  • 復(fù)制代碼 示例:
  • 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
  • 復(fù)制代碼

    總結(jié)

    以上是生活随笔為你收集整理的常用编码详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。