react-redux應用
ASCII及其擴充套件(字符集)
ASCII
ASCII使用 7位二進位制位 來表示一個字元,總共可以表示128個字元(即2^7,二進位制000 0000 ~ 111 1111 十進位制0~127)。
ASCII 擴充套件一
需求 :ASCII字符集是美國人發明的,這些字元完全是為其量身定製的。但隨著計算機技術的發展和普及,傳到了歐洲(如法國、德國)各國。由於歐洲很多國家中使用的字元除了ASCII表中的128個字元之外,還有一些各國特有的字元,於是歐洲人民發現ASCII字符集表達不了他們所要表達的東西呀。怎麼辦?
解決 :ASCII只使用了一個位元組(8位)之中的低7位,於是歐洲各國開始各顯神通,打起了那1個最高位(第0位)的主意,將 最高位
ASCII 擴充套件二(多位元組擴充套件)
編碼名稱 | 釋出時間 | 位元組數 | 漢字範圍 |
---|---|---|---|
GB2312 | 1980 | 變位元組(ASCII 1位元組,漢字2位元組 | 6763 |
GB13000 | 1993 | 變位元組(ASCII 1位元組,漢字2位元組 | 20902 |
GBK(CP936) | win95 | 2個位元組 | 21886 |
GB18030 | 2000 | 變位元組(ASCII 1位元組,漢字2位元組或4位元組 | 27484 |
ASCII 擴充套件三 (ANSI)
世界各國針對ASCII的擴充套件方案(如歐洲的ISO/IEC 8859,中國的GB系列等),這些 ASCII擴充套件編碼方案
在windows作業系統上,預設使用ANSI來儲存檔案。那麼作業系統是如何知道ANSI到底應該表示哪種編碼了,是GBK,還是ASCII,或者還是EUC-KR了? windows通過一個叫 "Code Page" (翻譯為中文就叫內碼表)的東西來判斷系統的預設編碼。簡體中文作業系統預設的內碼表是936,它表示ANSI使用的是GBK編碼。GB18030編碼對應的windows內碼表為CP54936。
可以使用 命令chcp 來檢視系統預設的內碼表。
Unicode統一碼標準(字元編碼)
需求 :各個國家使用不同的編碼規則,雖然他們都是相容ASCII的,但它們相互卻是不相容的。
Unicode字符集和ASCII字符集一樣,也只是一個字元集合,標記著字元和數字之間的對映關係,它不包含任何編碼規則和方案。和ASCII不一樣的是,Unicode字符集支援的字元數量是沒有限制的。
那麼Unicode字元是怎樣被編碼成記憶體中的位元組的了?它是通過UTF(Unicode Transformation Formats)實現的,比較常見得有UTF-8,UTF-16。
UTF-8
UTF-8編碼規則 :
- 對於ASCII(單位元組字元)字元,採用和ASCII相同的編碼方式,即只使用一個位元組表示,且該位元組第一位為0.
- 對於多位元組(2~4位元組)字元,假設位元組數為n(1 < n <= 4),第一個位元組:前n位都設為1,第n+1位設為0;後面的n-1個位元組的前兩位一律設為10。所有位元組中的沒有提及的其他二進位制位,全部為這個符號的unicode碼。
UTF-8帶BOM(Byte Order Mark)
“微軟在自己的UTF-8格式的文字檔案之前加上了EF BB BF三個位元組, windows上面的notepad等程式就是根據這三個位元組來確定一個文字檔案是ASCII的還是UTF-8的, 然而這個只是 微軟暗自作的標記 , 其它平臺上並沒有對UTF-8文字檔案做個這樣的標記。”
編碼 | ‘ABC’ |
---|---|
UTF-16BE(Without BOM) | 00 41 00 42 00 43 |
UTF-16LE(Without BOM) | 41 00 42 00 43 00 |
UTF-16BE(Without BOM) | FE FF 00 41 00 42 00 43 |
UTF-16LE(Without BOM) | FF FE 41 00 42 00 43 00 |
在windows系統上漢字預設使用CP936(即GBK編碼),佔2個位元組。而大多數Unicode字元的Unicode碼值也佔2個位元組,所以大多數人誤以為漢字字串在記憶體中的值就是Unicode值,這是錯誤的。
可以從 站長工具-Unicode 查詢漢字的Unicode碼值。
其它
全形與半形
因為漢字在顯示器上的顯示寬度要比英文字元的寬度要寬一倍,在一起排版顯示時不太美觀。所以GB編碼不僅僅加入了漢字字元,而且包括了ASCII字符集中本來就有的數字、標點符號、字母等字元。這些被編入GB編碼的數字、標點、字母在顯示器上的顯示寬度比ASCII字符集中的寬度寬一倍,所以前者稱為全形字元,後者稱為半形字元。
Windows 轉換介面
Windows API
//寬位元組(Windows內UTF-16) -> 多位元組編碼(ASCII/UTF-8等)
int WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar
);
// 多位元組編碼(ASCII/UTF-8等) -> 寬位元組(Windows內UTF-16)
int MultiByteToWideChar(
UINT CodePage,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar
);
介面封裝
std::string UnicodeToANSI(const std::wstring &str, UINT iCodePage = CP_ACP) {
std::string strRes;
int iSize = ::WideCharToMultiByte(iCodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
if (iSize == 0)
return strRes;
char *szBuf = new (std::nothrow) char[iSize];
if (!szBuf)
return strRes;
memset(szBuf, 0, iSize);
::WideCharToMultiByte(iCodePage, 0, str.c_str(), -1, szBuf, iSize, NULL, NULL);
strRes = szBuf;
delete[] szBuf;
return strRes;
}
std::wstring ANSIToUnicode(const std::string &str, UINT iCodePage = CP_ACP) {
std::wstring strRes;
int iSize = ::MultiByteToWideChar(iCodePage, 0, str.c_str(), -1, NULL, 0);
if (iSize == 0)
return strRes;
wchar_t *szBuf = new (std::nothrow) wchar_t[iSize];
if (!szBuf)
return strRes;
memset(szBuf, 0, iSize * sizeof(wchar_t));
::MultiByteToWideChar(iCodePage, 0, str.c_str(), -1, szBuf, iSize);
strRes = szBuf;
delete[] szBuf;
return strRes;
}
std::string UnicodeToUTF8(const std::wstring &str) {
std::string strRes;
int iSize = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
if (iSize == 0)
return strRes;
char *szBuf = new (std::nothrow) char[iSize];
if (!szBuf)
return strRes;
memset(szBuf, 0, iSize);
::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, szBuf, iSize, NULL, NULL);
strRes = szBuf;
delete[] szBuf;
return strRes;
}
std::string UnicodeToUTF8BOM(const std::wstring &str) {
std::string strRes;
int iSize = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
if (iSize == 0)
return strRes;
unsigned char *szBuf = new (std::nothrow) unsigned char[iSize + 3];
if (!szBuf)
return strRes;
memset(szBuf, 0, iSize + 3);
if (::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, (LPSTR)(szBuf + 3), iSize, NULL, NULL) > 0) {
szBuf[0] = 0xEF;
szBuf[1] = 0xBB;
szBuf[2] = 0xBF;
}
strRes = (char*)szBuf;
delete[] szBuf;
return strRes;
}
std::wstring UTF8ToUnicode(const std::string &str) {
std::wstring strRes;
int iSize = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
if (iSize == 0)
return strRes;
wchar_t *szBuf = new (std::nothrow) wchar_t[iSize];
if (!szBuf)
return strRes;
memset(szBuf, 0, iSize * sizeof(wchar_t));
::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, szBuf, iSize);
strRes = szBuf;
delete[] szBuf;
return strRes;
}
std::string ANSIToUTF8(const std::string &str, UINT iCodePage = CP_ACP) {
return UnicodeToUTF8(ANSIToUnicode(str, iCodePage));
}
std::string ANSIToUTF8BOM(const std::string &str, UINT iCodePage = CP_ACP) {
return UnicodeToUTF8BOM(ANSIToUnicode(str, iCodePage));
}
std::string UTF8ToANSI(const std::string &str, UINT iCodePage = CP_ACP) {
return UnicodeToANSI(UTF8ToUnicode(str), iCodePage);
}
在windows下避免亂碼
通過第3節的說明,很容易知道,要開發支援多語言,在任意語言(系統內碼表)的windows環境下都正常編譯,且執行起來沒有亂碼的程式,需要遵循如下原則:
- 程式碼檔案採用UTF-8 with BOM編碼。
- Visual Studio字符集設定為Unicode字符集。
- 使用wchar_t。