預(yù)備知識(shí)
參考這兩個(gè)連接
從Emoji的限制到Unicode編碼
帶你玩轉(zhuǎn)Visual Studio——帶你理解多字節(jié)編碼與Unicode碼
vs studio c++ 項(xiàng)目目前只有兩種編碼格式,多字節(jié)和Unicode,默認(rèn)都是多字節(jié)袭景,這個(gè)有好處就是char兼容ascii 編碼汗菜,缺點(diǎn)是當(dāng)我們賦值其他國家語言時(shí)候就不能直接賦值了比如
// 多字節(jié)編碼
void TestChar()
{
char ch1 = 's'; // 正確
cout << "ch1:" << ch1 << endl;
char ch2 = '中'; // 錯(cuò)誤,一個(gè)char不能完整存放一個(gè)漢字信息
cout << "ch2:" << ch2 << endl;
char str[4] = "中"; //前三個(gè)字節(jié)存放漢字'中',最后一個(gè)字節(jié)存放字符串結(jié)束符\0
cout << "str:" << str << endl;
//char str2[2] = "國"; // 錯(cuò)誤:'str2' : array bounds overflow
//cout << str2 << endl;
}
// Unicode 編碼
void TestWchar_t()
{
wcout.imbue(locale("chs")); // 將wcout的本地化語言設(shè)置為中文
wchar_t wch1 = L's'; // 正確
wcout << "wch1:" << wch1 << endl;
wchar_t wch2 = L'中'; // 正確,一個(gè)漢字用一個(gè)wchar_t表示
wcout << "wch2:" << wch2 << endl;
wchar_t wstr[2] = L"中"; // 前兩個(gè)字節(jié)(前一個(gè)wchar_t)存放漢字'中',最后兩個(gè)字節(jié)(后一個(gè)wchar_t)存放字符串結(jié)束符\0
wcout << "wstr:" << wstr << endl;
wchar_t wstr2[3] = L"中國";
wcout << "wstr2:" << wstr2 << endl;
}
多字節(jié) 處理編碼
一般的項(xiàng)目選擇多字節(jié)后地淀,默認(rèn)編碼(我的是簡(jiǎn)體中文的vs studio 2013)是gb2312,可以從高級(jí)保存里面看到當(dāng)前的文件的編碼格式梧疲。
編碼
這個(gè)時(shí)候我們可以調(diào)出我們的內(nèi)存查看器查看我們的中國
的編碼是
d6 d0 b9 fa
GB2312
我們可以在這個(gè)網(wǎng)址在線編碼看到如下結(jié)果
中國
Unicode 編碼是 :
0x4E2D 0x56FD
utf8 編碼是
e4 b8 ad e5 9b bd
我們可以根據(jù)這個(gè)函數(shù)來轉(zhuǎn)為utf8 ,一般本地字符串這個(gè)不會(huì)導(dǎo)致亂碼
string GBKToUTF8(const char* strGBK)
{
int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
string strTemp = str;
if (wstr) delete[] wstr;
if (str) delete[] str;
return strTemp;
}
但是通常我們會(huì)從數(shù)據(jù)庫取數(shù)據(jù)擦耀,這個(gè)坑就比較多了饼酿,我用的是ado 來從sql server 獲取nvarchar 的數(shù)據(jù)獲取的結(jié)果如下:
可以看到我們獲取的數(shù)據(jù)是Unicode的編碼格式的榕酒,所以我們要直接轉(zhuǎn)成utf8就行了不需要轉(zhuǎn)成Unicode了。
這里有必要說下故俐,ado 操作數(shù)據(jù)庫有
遍歷結(jié)果集
和傳入?yún)?shù)
獲取值想鹰,我目前發(fā)現(xiàn)使用結(jié)果集獲取的是Unicode 編碼,傳入?yún)?shù)之前項(xiàng)目碰到過亂碼了药版,所以建議使用結(jié)果集辑舷。
tips
這里怎么調(diào)出內(nèi)存查看器和高級(jí)保存選項(xiàng),大家可以自己搜索下槽片,自己動(dòng)手多學(xué)習(xí)學(xué)習(xí)下何缓,我就不寫入里面了。
附錄:
Unicode 轉(zhuǎn)utf8 的函數(shù)
bool Unicode2UTF(vector<char> &Dest, wchar_t *szSrc)
{
int iTextLen = wcslen(szSrc);
if (iTextLen == 0)
{
return false;
}
iTextLen = WideCharToMultiByte(CP_UTF8,
0,
(LPWSTR)szSrc,
-1,
NULL,
0,
NULL,
NULL);
if (iTextLen == 0)
return false;
Dest.resize(iTextLen);
::WideCharToMultiByte(CP_UTF8,
0,
(LPWSTR)szSrc,
-1,
&*Dest.begin(),
iTextLen,
NULL,
NULL);
return true;
}
Windows API函數(shù)MultiByteToWideChar用于多字節(jié)編碼字符串向?qū)捵址碪TF-16 LE)的轉(zhuǎn)碼还栓。它的第一個(gè)參數(shù)的常用值是CP_ACP和CP_OEMCP碌廓。
CP_ACP和CP_OEMCP,分別是指當(dāng)前計(jì)算機(jī)上的Windows操作系統(tǒng)的Windows代碼頁與OEM代碼頁剩盒。對(duì)于東亞的簡(jiǎn)體中文谷婆、繁體中文、日文、韓文等Win操作系統(tǒng)語言環(huán)境波材,這兩種代碼頁是同一個(gè)股淡,如簡(jiǎn)體中文是代碼頁936即GB2312字符集,繁體中文是950即大五碼字符集廷区,韓文是949唯灵、日文是932。對(duì)于西方國家的拼音文字語言設(shè)置隙轻,兩個(gè)代碼頁不同埠帕。典型的如English_US,其Windows代碼頁是1252玖绿、OEM代碼頁是437敛瓷,還有第三個(gè)代碼頁ISO-8859-1又稱Latin-1或“西歐語言”,是針對(duì)英語法語西語德語等西歐語言的擴(kuò)展ASCII字符集斑匪。這三者(1252呐籽、437、8859-1)都是針對(duì)英語但并不相同蚀瘸。
編碼轉(zhuǎn)換規(guī)則
Unicode轉(zhuǎn)UFT-8:設(shè)置WideCharToMultiByte的CodePage參數(shù)為CP_UTF8
Unicode轉(zhuǎn)ANSI:設(shè)置WideCharToMultiByte的CodePage參數(shù)為CP_ACP
UTF-8轉(zhuǎn)Unicode:設(shè)置MultiByteToWideChar的CodePage參數(shù)為CP_UTF8
ANSI轉(zhuǎn)Unicode:設(shè)置MultiByteToWideChar的CodePage參數(shù)為CP_ACP
UTF-8轉(zhuǎn)ANSI:先將UTF-8轉(zhuǎn)換為Unicode狡蝶,再將Unicode轉(zhuǎn)換成ANSI
ANSI轉(zhuǎn)UTF-8:先將ANSI轉(zhuǎn)換為Unciode,再將Unicode轉(zhuǎn)換成ANSI贮勃。
ANSI 這里并不是嚴(yán)格的贪惹,是ANSI的拓展,指的是本地的編碼寂嘉,如中文就是GB2312