字符串編碼問題(Ascii、Unicode、UCS-2、GBK、UTF-8)

1.字符編碼的發展

第一階段:ASCII階段,(American Standard Code for Information Interchange, “美國信息交換標準碼),計算機當時只支持英語,字符在計算機中都是以0和1的方式存儲的。象a、b、c、d這樣的52個字母(包括大寫)、以及0、1、2等數字還有一些常用的符號(例如*、#、@等)在計算機中存儲時也要使用二進制數來表示,而具體用哪些二進制數字表示哪個符號,就必須要有一定的規則,於是美國有關的標準化組織就出臺了所謂的ASCII編碼,統一規定了上述常用符號用哪個二進制數來表示。(來自百度百科),ASCII碼規定每個字符例如“a”使用1個字節來表示,也就是8爲的二進制組合,那麼就有00000000-11111111一共256種組合,也就是可以表示256個不同的字符。

其中0-31:是控制字符或通訊專用字符(不可以顯示的字符,其餘爲可顯示字符),如控制符:LF(換行)、CR(回車)等。

32-126:是字符,其中32是空格。

48-57爲0-9的阿拉伯數字。

65-90爲26個大寫英文字母。

97-122爲26個小寫英文字母。

其餘的是一些標點符號,運算符號等。

ASSCII共計有128個,從0到127,也就是從00000000-01111111,最高位都是0。

 

第二階段:ANSI編碼(本地化)階段,ASCII只能表示英文字符,那麼其他字符怎麼表示呢?漢語是這樣解決的,用兩個ASCII表示一個漢字,而且不用前面的128個。比如漢字“中”在中文操作系統中使用[0xD6,0xD0] 這兩個字節存儲,這樣每個漢字也都有了自己的編碼,漢字編碼解決了,這就是中國的GB2312編碼標準,但是這是中國漢字的編碼,那麼其他國家呢?其他的國家的計算機操作系統中可能把[0xD6,0xD0] 這兩個字節存儲成他們的文字,而不是“中”,不同的國家和地區制定了不同的標準,這些使用 2 個字節來代表一個字符的各種文字延伸編碼方式,稱爲 ANSI 編碼

(1)GB2312-80漢字編碼
GB2312國標字符集構成一個二維平面,它分成94行、94列,行號稱爲區號,列號稱爲位號。每一個漢字或符號在碼錶中都有各自的位置,字符的位置用它所在的區號(行號)及位號(列號)來表示。每個漢字的區號和位號分別用1個字節來表示,
如:“大”字的區號20,位號83,區位碼是20,83
用2個字節表示爲:00010100 01010011
問題:信息通信中,漢字的區位碼與通信使用的控制碼(00H~1FH)發生衝突。
解決方案:爲避免漢字區位碼與通信控制碼衝突,ISO2022規定,每個漢字區號和位號必須分別加上32(即20H),
即區位碼加上2020H。
經過這樣處理得到的代碼稱爲漢字的國標交換碼(簡稱交換碼)。因此,字的國際交換碼是:
區位碼(00010100 01010011)+ 2020H=國際交換碼(00110100 01110011)
 
機內碼
問題:文本中漢字與西文字符經常混用,漢字信息如不予以特別的標識,它與單字節的標準ASCII碼就會混淆不清。
解決方法:把一個漢字看作兩個擴展ASCII碼,使表示GB2312漢字的兩個字節的最高位(b7)加“1”,(即27=128=80H)。這種高位爲l的雙字節(16位)漢字編碼就稱爲GB2312漢字的機內碼,又稱內碼。
“大”的國際交換碼:(00110100 01110011),
內碼是:10110100 11110011(B4F3)

 

第三階段:UNICODE(國際化),爲了使國際間信息交流更加方便,國際組織制定了 UNICODE 字符集,爲各種語言中的每一個字符設定了統一併且唯一的數字編號,以滿足跨語言、跨平臺進行文本轉換、處理的要求。Unicode用數字0-0x10FFFF來映射這些字符,最多可以容納1114112個字符,或者說有1114112個碼位。碼位就是可以分配給字符的數字。UTF-8、UTF-16、UTF-32都是將數字轉換到程序數據的編碼方案。

Unicode目前普遍採用的是UCS-2它用兩個字節來編碼一個字符一般用十六進制來表示UCS-2最多能編碼65536個字符

 

環境:win7中文旗艦版 + VS2010 + 當前代碼頁爲GBK(GBK兼容GB2312,所以上面的例子,可以再當前環境下驗證)

 

string str1 = "123大";//GBK編碼[31H,32H,33H,b4H,f3H]
wstring str2 = L"123大";//UCS-2編碼[0031H,0032H,0033H,5927H]
string str3;
int nlength = WideCharToMultiByte(CP_UTF8, 0, str2.c_str(), -1, NULL, 0, NULL, NULL);
str3.resize(nlength, '\0');
WideCharToMultiByte(CP_UTF8, 0, str2.c_str(), -1, &str3[0], nlength, NULL, NULL);//Unicode to UTF-8
//str2 UTF-8編碼[31H,32H,33H,E5H,a4H,a7H]


1)對於單字節的符號,字節的第一位設爲0,後面7位爲這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。

2)對於n字節的符號(n>1),第一個字節的前n位都設爲1,第n+1位設爲0,後面字節的前兩位一律設爲10。剩下的沒有提及的二進制位,全部爲這個符號的unicode碼。

例如:

“大”字,UCS-2編碼爲[5927H],即[0101 1001 0010 0111]

對於UTF-8編碼來說,[5927H]在0800H~FFFFH之間,應該使用[1110 xxxx 10yy yyyy 10zz zzzz],將[0101 1001 0010 0111]以此填入xxxx yy yyyy zz zzzz部分,得

[1110 0101 1010 0100 1010 0111],即 [e5H a4H a7H]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章