第11節 ANSI編碼程序員
爲使計算機支持更多語言,一般使用 0x80~0xFF 範圍的 2 個字節來表示 1 個字符。好比:漢字 '中' 在中文操做系統中,使用 [0xD6,0xD0] 這兩個字節存儲。數組
不一樣的國家和地區制定了不一樣的標準,由此產生了 GB23十二、GBK、GB18030、Big五、Shift_JIS 等各自的編碼標準。這些使用多個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼。在簡體中文Windows操做系統中,ANSI 編碼表明 GBK 編碼;在繁體中文Windows操做系統中,ANSI編碼表明Big5;在日文Windows操做系統中,ANSI 編碼表明 Shift_JIS 編碼。編輯器
不一樣 ANSI 編碼之間互不兼容,當信息在國際間交流時,沒法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。ide
ANSI編碼表示英文字符時用一個字節,表示中文用兩個或四個字節。函數
第12節 全角和半角測試
全角(大陸、日本、韓國稱全角;臺灣、香港稱全形;也稱全寬或全碼)和半角(大陸、日本、韓國稱半角;臺灣、香港稱半形;也稱半寬或半碼),是計算機中,中、日、韓文的CJKV字符的顯示格式。字體
傳統上,英語或拉丁字母語言使用的電腦系統,每個字母或符號,都是使用一字節的空間(一字節由8位元組成,共256個編碼空間)來儲存;而漢語、日語及韓語文字,因爲數量大大超過256個,故慣常使用兩字節來儲存一個字符,在使用固定寬度文字的地方(如DOS、部分文字編輯器等),爲了使字體看起來齊整,英文字母、數字及其餘符號,也由原來只佔一個字空間,改成一律佔用兩個字的空間來顯示,而且使用兩個字節來儲存。因此,中、日、韓等文字稱爲全形字符,相比起來,拉丁字母或數字就稱爲半形字符。ui
JIS X 0201編碼表把日語的片假名放進一字節的空間,故又稱爲「半角片假名」。編碼
半形假名spa
半形假名(日文:半角カナ)是對 JIS X 0201 標準收納的片假名、幾個基本日文標點符號(日文:句読點 或 約物)、濁點和半濁點的統稱。其包含日文的最基礎符號,能以最簡約的方式表達日語。每一個「半形假名」只須要八位元,能夠當作是對 ISO 646 / ASCII 的擴充;佔用的文字寬度亦同樣,一般只有普通漢字的一半,故稱爲「半形假名」。
例如普通(全形)的片假名「カ」,半形的是「カ」。平假名和漢字並沒有半形版本。
區位碼
區位碼是指每一個漢字的GB2312編碼的對應表示,以4位十進制數字表示。例如「啊」字的區位碼是1601。
國標碼的內碼是指每一個漢字未經處理的GB2312編碼,以4位十六進制數字表示。例如「啊」字的國標碼是B0A1(與國標碼對比:0xB0=0xA0+16,0xA1=0xA0+1)。
國標碼、區位碼都屬於「無理碼」(即沒有什麼道理可講,就得背),直接向計算機輸入區位碼而獲得漢字的方法叫作區位輸入法(相應地,輸入國標碼而獲得漢字的方法叫作GB內碼輸入法)。在DOS時代,許多中文系統都實現了國標碼及區位碼輸入法,以便程序員進行輸入測試。普通用戶通常不使用這些輸入法,在DOS被Windows系統取代後,國標碼和區位碼輸入法已經趨於消亡。
Windows 95至2000、Me中,有「區位輸入法」和「內碼輸入法」;Windows XP中,有「中文(簡體) - 內碼」;Windows Vista起,該輸入法被移除,須從XP系統中移植WinGB.IME方可以使用。
MBCS(Multi-Byte Chactacter System,即多字節字符系統)
它是編碼的一種類型,而不是某個特定編碼的名稱。
字符基礎:ASCII,DBCS,Unicode
全部的string類都是以C-style字符串爲基礎的。C-style字符串是字符數組。字符類型有三種編碼格式:
第一種是單字節字符集(single byte character set or SBCS)。在這種編碼格式下,全部字符都只用 一個字節表示,ASCII碼就是單字節字符。用"0"來表示一個字節的結束。
第二種編碼格式是多字節字符集(multi-byte character set or MBCS)。在Windows裏的MBCS包含兩種字符類型:單字節字符(single byte characters)和雙字節字符(double byte characters)。因爲Windows 裏使用的多字節字符絕大部分是兩個字節長,MBCS常被DBCS代替。
第三種編碼格式是Unicode。Unicode是一種全部的字符都使用兩個字節編碼的編碼模式。Unicode字符有時也被稱做寬字符。
Unicode與MBCS的區別是:MBCS字符可使用不一樣長度的字節編碼。
單字節字符包含拉丁文字母表及ASCII碼和DOS操做系統定義的圖形字符。雙字節字符被用來表示東亞及中東的語言。Unicode被用來COM及Windows NT操做系統內部。
char是單字節字符。雙字節字符也能夠用char類型來進行操做。Unicode字符用wchar_t來表示。Unicode字符和字符串常量用前綴L來表示。例如:
wchar_t wch = L"1";
wchar_t* wsz = L"Hello";
單字節字符串在內存中:每一個字符佔一個字節按順序依次存儲。最後以單字節表示的0結束。例如:"Bob"在內存中的存儲形式:
|-------------------------------|
|42 | 6F | 62 | 00 |
|-------------------------------|
|B | o | b | BOS |
|-------------------------------|
Unicode的存儲形式:
--------------------------------------------
| 42 00 | 6F 00 | 62 00 | 00 00 |
|------------------------------------------|
| B | o | b | BOS |
|------------------------------------------|
Win32 API中的MBCS和Unicode
儘管你也許歷來沒有注意過,Win32中的每一個與字符串相關的API和message都有兩個版本。一個版本按受MBCS字符串,另外一個接受Unicode字符串。例如:根本沒有SetWindowText()這個API,相反有SetWindowTextA()和SetWindowTextW()。
後綴A代表這是MBCS函數,後綴W表示這是Unicode版本的函數。
當你build一個Windows程序,你能夠選擇是用MBCS或者Unicode API,若是你用vc嚮導而且沒有改過預處理的設置。那代表你用的是MBCS版本。
當使用MBCS API來build程序時,UNICODE沒有被定義,因此預處理器看到:
#define SetWindowText SetWindowTextA
這個宏把全部對SetWindowText的調用都轉換成真正的API函數SetWindowTextA.若是你想把默認使用的API函數變成Unicode版的,你能夠在預處理器設置中,把_MBCS從預約義的宏列表中刪除。而後添加UNICODE和_UNICODE(須要兩個都定義,由於不一樣的頭文件可能使用不一樣的宏。)
使用TCHAR類型
TCHAR是一種字符串類型,它讓你在以MBCS和UNICODE來build程序時可使用一樣的代碼;不須要使用繁瑣的宏定義來包含你的代碼。TCHAR的定義以下:
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
還有一個宏來處理定義Unicode字符串常量時所需的L前綴。
#ifdef UNICODE
#define _T(x) L##X
#else
#define _T(x)x
#endif
##是一個預處理操做符,它能夠把兩個參數連在一塊兒。若是你的代碼中須要字符串常量,在它前面加上_T宏,若是你使用Unicode來build,它會在字符串常量前加上L前綴。
Windows API是用TCHAR來定義的,在編譯時,它能夠根據你是否認義_MBCS或_UNICODE被編譯成MBCS或者Unicode字符。
類型 含義
WCHAR Unicode character(wchar_t)
TCHAR MBCS or Unicode character.
LPSTR string of char (char*)
LPCSTR const string of char(const char*)
LPWSTR string of WCHAR(WCHAR*)
LPCWSTR constant string of WCHAR(const WCHAR*)
LPTSTR string of TCHAR(TCHAR*)
LPCTSTR constant string of TCHAR(const TCHAR*)
雜談:
計算機發明後,爲了在計算機中表示字符,人們制定了一種編碼,叫作ASCII碼,ASCII碼由一個字節中的7位(bit)表示,範圍是0x00-0x7F共128個字符。用這128個數字表示abcd...ABCD...1234....這些字符。後來又擴展了ASCII碼的定義,使用一個字節的所有8位(bit)來表示字符了。這就叫擴展 ASCII碼。範圍是0x00-0xFF共256個字符。
後來,中國人利用連續2個擴展ASCII碼的擴展區域(0xA0之後)來表示一個漢字,該方法的標準叫GB-2312。後來,日文、韓文、阿拉伯文、臺灣繁體都使用相似的方法擴展了本地字符集的定義,如今統一稱爲MBCS字符集(多字節字符集)。這種方法是有缺陷的,由於各個國家的定義的字符集有交集,所以使用GB2312的軟件,就不能在BIG-5的環境下運行(顯示亂碼)。
爲了把全世界的全部的文字符號都統一進行編碼,因而制定了UNICODE標準字符集。UNICODE使用2個字節表示一個字符。這下終於好啦,全世界任何一個地區的軟件,能夠 不用修改就能在另外一個地區運行了。UNICODE的範圍是0x0000-0xFFFF共6萬多個字符。
在程序中使用各類字符集的方法:
const char* p = "Hello"; //使用ASCII碼
const char* p = "你好"; //使用MBCS字符集,因爲MBCS徹底兼容ASCII碼,多數狀況,咱們並不嚴格區分他們。
LPCSTR p = "Hello,你好"; //意義同上。
const WCHAR *p = L"Hello,你好";使用UNICODE字符集。
//若是預約義了_UNICODE,則表示使用UNICODE字符集,若是定義了_MBCS,則表示使用MBCS
const TCHAR *p = _T("Hello 您好");
LPCTSTR p = _T("Hello,你好");//意義同上。
多字節與UTF-八、Unicode之間的轉換
// 多字節編碼轉爲UTF8編碼 bool MBToUTF8(vector<char>& pu8, const char* pmb, int32 mLen) { // convert an MBCS string to widechar int32 nLen = MultiByteToWideChar(CP_ACP, 0, pmb, mLen, NULL, 0); WCHAR* lpszW = NULL; try { lpszW = new WCHAR[nLen]; } catch(bad_alloc &memExp) { return false; } int32 nRtn = MultiByteToWideChar(CP_ACP, 0, pmb, mLen, lpszW, nLen); if(nRtn != nLen) { delete[] lpszW; return false; } // convert an widechar string to utf8 int32 utf8Len = WideCharToMultiByte(CP_UTF8, 0, lpszW, nLen, NULL, 0, NULL, NULL); if (utf8Len <= 0) { return false; } pu8.resize(utf8Len); nRtn = WideCharToMultiByte(CP_UTF8, 0, lpszW, nLen, &*pu8.begin(), utf8Len, NULL, NULL); delete[] lpszW; if (nRtn != utf8Len) { pu8.clear(); return false; } return true; } // UTF8編碼轉爲多字節編碼 bool UTF8ToMB(vector<char>& pmb, const char* pu8, int32 utf8Len) { // convert an UTF8 string to widechar int32 nLen = MultiByteToWideChar(CP_UTF8, 0, pu8, utf8Len, NULL, 0); WCHAR* lpszW = NULL; try { lpszW = new WCHAR[nLen]; } catch(bad_alloc &memExp) { return false; } int32 nRtn = MultiByteToWideChar(CP_UTF8, 0, pu8, utf8Len, lpszW, nLen); if(nRtn != nLen) { delete[] lpszW; return false; } // convert an widechar string to Multibyte int32 MBLen = WideCharToMultiByte(CP_ACP, 0, lpszW, nLen, NULL, 0, NULL, NULL); if (MBLen <=0) { return false; } pmb.resize(MBLen); nRtn = WideCharToMultiByte(CP_ACP, 0, lpszW, nLen, &*pmb.begin(), MBLen, NULL, NULL); delete[] lpszW; if(nRtn != MBLen) { pmb.clear(); return false; } return true; } // 多字節編碼轉爲Unicode編碼 bool MBToUnicode(vector<wchar_t>& pun, const char* pmb, int32 mLen) { // convert an MBCS string to widechar int32 uLen = MultiByteToWideChar(CP_ACP, 0, pmb, mLen, NULL, 0); if (uLen<=0) { return false; } pun.resize(uLen); int32 nRtn = MultiByteToWideChar(CP_ACP, 0, pmb, mLen, &*pun.begin(), uLen); if (nRtn != uLen) { pun.clear(); return false; } return true; } //Unicode編碼轉爲多字節編碼 bool UnicodeToMB(vector<char>& pmb, const wchar_t* pun, int32 uLen) { // convert an widechar string to Multibyte int32 MBLen = WideCharToMultiByte(CP_ACP, 0, pun, uLen, NULL, 0, NULL, NULL); if (MBLen <=0) { return false; } pmb.resize(MBLen); int nRtn = WideCharToMultiByte(CP_ACP, 0, pun, uLen, &*pmb.begin(), MBLen, NULL, NULL); if(nRtn != MBLen) { pmb.clear(); return false; } return true; } // UTF8編碼轉爲Unicode bool UTF8ToUnicode(vector<wchar_t>& pun, const char* pu8, int32 utf8Len) { // convert an UTF8 string to widechar int32 nLen = MultiByteToWideChar(CP_UTF8, 0, pu8, utf8Len, NULL, 0); if (nLen <=0) { return false; } pun.resize(nLen); int32 nRtn = MultiByteToWideChar(CP_UTF8, 0, pu8, utf8Len, &*pun.begin(), nLen); if(nRtn != nLen) { pun.clear(); return false; } return true; } // Unicode編碼轉爲UTF8 bool UnicodeToUTF8(vector<char>& pu8, const wchar_t* pun, int32 uLen) { // convert an widechar string to utf8 int32 utf8Len = WideCharToMultiByte(CP_UTF8, 0, pun, uLen, NULL, 0, NULL, NULL); if (utf8Len<=0) { return false; } pu8.resize(utf8Len); int32 nRtn = WideCharToMultiByte(CP_UTF8, 0, pun, uLen, &*pu8.begin(), utf8Len, NULL, NULL); if (nRtn != utf8Len) { pu8.clear(); return false; } return true; }