Windows系統上的 Notepad.exe 打開文件后,點擊“文件”菜單中的“另存為”命令,會跳出一個對話框,在最底部有一個“編碼”的下拉條。
里面有四個選項:ANSI,Unicode,Unicode big endian 和 UTF-8。
1)ANSI是默認的編碼方式。對於英文文件是ASCII編碼,對於簡體中文文件是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會采用Big5碼)。
2)Unicode編碼指的是UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。這個選項用的little endian格式。
3)Unicode big endian編碼與上一個選項相對應。我在下一節會解釋little endian和big endian的涵義。
4)UTF-8編碼,也就是上一節談到的編碼方法。
缺省的編譯選項下,編譯器認為String就是AnsiString字符串(可以使用$H編譯開關來進行修改)。
AnsiString 這是Pascal缺省的字符串類型,它由AnsiChar 字符組成,其長度沒有限制,同時與null結束的字符串相兼容,它的內存和ANSI編碼格式的TXT文件的內存一樣,AnsiString可能是全部都是ASCII字符,也可能包含中文字符。
如果是在繁體中文windows系統上,可能包含繁體中文字符,如果是簡體中文系統,則為GB2312編碼,如果是繁體中文系統,則為BIG 5碼。
WideString功能上類似於AnsiString,但它是由WideChar字符(UniCode字符集)組成的。引入這種類型,主要是為了支持OLE編程。而且還有一個實用的功能,就是當一個字符串是中英文字符混雜時,能夠准確計數字符數,並可分別訪問其中每一個中文字符或英文字符,如果一個AnsiString中含有中英文字符時,就不容易確定字符數,也無法准確訪問其中的每一個字符。AnisString字符串的每一個字節都不為零,但WideString的內存字節可能為0。AnsiString內存字節中,有可能一個字節代表一個字符,也可能兩個字節代表一個字符,WideString全部是兩個字節代表一個字符。
可以將一個WideString賦給一個AnsiString,也可以將一個AnsiString賦給一個WideString,在賦值過程中將發生編碼轉換,如果一個WideString中的Unicode字符在ANSI字符集編碼范圍之外,則該Unicode字符被轉為? (0x3F),所以就會出現拷貝一些阿拉伯字符串到文本框中后變成一串?的情況。
Unicode編碼則是采用雙字節16位來進行編號,可編65536字符,基本上包含了世界上所有的語言字符,它也就成為了全世界一種通用的編碼,而且用十六進制4位表示一個編碼,非常簡結直觀,為大多數開發者所接受。
AnsiString(或長字符串)類型是在Delphi2.0開始引入的,因為Delphi 1.0的用戶特別需要一個容易使用而且沒有255個字符限制的字符串類型,而AnsiString正好能滿足這些要求。 雖然AnsiString在外表上跟以前的字符串類型幾乎相同,但它是動態分配的並有自動回收功能,正是因為這個功能AnsiString有時被稱為生存期自管理類型。Object Pascal能根據需要為字符串分配空間,所以不用像在C/C++中所擔心的為中間結果分配緩沖區。另外,AnsiString字符串總是以null字符結束的,這使得AnsiString字符串能與Win32 API 中的字符串兼容。實際上,AnsiString類型是一個指向在堆棧中的字符串結構的指針。
WideString類型像AnsiString一樣是生存期自管理類型,它們都能動態分配、自動回收並且彼此能相互兼容,不過WideString和AnsiString的不同主要在三個方面:
WideString由WideChar字符組成,而不是由AnsiChar字符組成的,它們跟Unicode字符串兼容。
WideString用SysAllocStrLen()API函數進行分配,它們跟OLE的BSTR字符串相兼容。
WideString沒有引用計數,所以將一個WideString字符串賦值給另一個WideString字符串時,就需要從內存中的一個位置復制到另一個位置。這使得WideString在速度和內存的利用上不如AnsiString有效。
Utf8String的定義同string, 但一般存放Utf8編碼的字符串。
UTF-8編碼
這是一種變長的編碼方式:它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度,當字符在ASCII碼的范圍時,就用一個字節表示,保留了ASCII字符一個字節的編碼做為它的一部分,如此一來UTF-8編碼也可以是為視為一種對ASCII碼的拓展。值得注意的是unicode編碼中一個中文字符占2個字節,而UTF-8一個中文字符占3個字節。從unicode到uft-8並不是直接的對應,而是要過一些算法和規則來轉換。
在計算機內存中,統一使用Unicode編碼,當需要保存到硬盤或者需要傳輸的時候,就轉換為UTF-8編碼。
用記事本編輯的時候,從文件讀取的UTF-8字符被轉換為Unicode字符到內存里,編輯完成后,保存的時候再把Unicode轉換為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]
————————————————
版權聲明:本文為CSDN博主「cbntrt」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/cbntrt/java/article/details/88605095