预备知识
参考这两个连接
从Emoji的限制到Unicode编码
带你玩转Visual Studio——带你理解多字节编码与Unicode码
vs studio c++ 项目目前只有两种编码格式,多字节和Unicode,默认都是多字节,这个有好处就是char兼容ascii 编码,缺点是当我们赋值其他国家语言时候就不能直接赋值了比如
// 多字节编码
void TestChar()
{
char ch1 = 's'; // 正确
cout << "ch1:" << ch1 << endl;
char ch2 = '中'; // 错误,一个char不能完整存放一个汉字信息
cout << "ch2:" << ch2 << endl;
char str[4] = "中"; //前三个字节存放汉字'中',最后一个字节存放字符串结束符\0
cout << "str:" << str << endl;
//char str2[2] = "国"; // 错误:'str2' : array bounds overflow
//cout << str2 << endl;
}
// Unicode 编码
void TestWchar_t()
{
wcout.imbue(locale("chs")); // 将wcout的本地化语言设置为中文
wchar_t wch1 = L's'; // 正确
wcout << "wch1:" << wch1 << endl;
wchar_t wch2 = L'中'; // 正确,一个汉字用一个wchar_t表示
wcout << "wch2:" << wch2 << endl;
wchar_t wstr[2] = L"中"; // 前两个字节(前一个wchar_t)存放汉字'中',最后两个字节(后一个wchar_t)存放字符串结束符\0
wcout << "wstr:" << wstr << endl;
wchar_t wstr2[3] = L"中国";
wcout << "wstr2:" << wstr2 << endl;
}
多字节 处理编码
一般的项目选择多字节后,默认编码(我的是简体中文的vs studio 2013)是gb2312,可以从高级保存里面看到当前的文件的编码格式。
这个时候我们可以调出我们的内存查看器查看我们的中国
的编码是
d6 d0 b9 fa
我们可以在这个网址在线编码看到如下结果
中国
Unicode 编码是 :
0x4E2D 0x56FD
utf8 编码是
e4 b8 ad e5 9b bd
我们可以根据这个函数来转为utf8 ,一般本地字符串这个不会导致乱码
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;
}
但是通常我们会从数据库取数据,这个坑就比较多了,我用的是ado 来从sql server 获取nvarchar 的数据获取的结果如下:
可以看到我们获取的数据是Unicode的编码格式的,所以我们要直接转成utf8就行了不需要转成Unicode了。
这里有必要说下,ado 操作数据库有
遍历结果集
和传入参数
获取值,我目前发现使用结果集获取的是Unicode 编码,传入参数之前项目碰到过乱码了,所以建议使用结果集。
tips
这里怎么调出内存查看器和高级保存选项,大家可以自己搜索下,自己动手多学习学习下,我就不写入里面了。
附录:
Unicode 转utf8 的函数
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函数MultiByteToWideChar用于多字节编码字符串向宽字符串(即UTF-16 LE)的转码。它的第一个参数的常用值是CP_ACP和CP_OEMCP。
CP_ACP和CP_OEMCP,分别是指当前计算机上的Windows操作系统的Windows代码页与OEM代码页。对于东亚的简体中文、繁体中文、日文、韩文等Win操作系统语言环境,这两种代码页是同一个,如简体中文是代码页936即GB2312字符集,繁体中文是950即大五码字符集,韩文是949、日文是932。对于西方国家的拼音文字语言设置,两个代码页不同。典型的如English_US,其Windows代码页是1252、OEM代码页是437,还有第三个代码页ISO-8859-1又称Latin-1或“西欧语言”,是针对英语法语西语德语等西欧语言的扩展ASCII字符集。这三者(1252、437、8859-1)都是针对英语但并不相同。
编码转换规则
Unicode转UFT-8:设置WideCharToMultiByte的CodePage参数为CP_UTF8
Unicode转ANSI:设置WideCharToMultiByte的CodePage参数为CP_ACP
UTF-8转Unicode:设置MultiByteToWideChar的CodePage参数为CP_UTF8
ANSI转Unicode:设置MultiByteToWideChar的CodePage参数为CP_ACP
UTF-8转ANSI:先将UTF-8转换为Unicode,再将Unicode转换成ANSI
ANSI转UTF-8:先将ANSI转换为Unciode,再将Unicode转换成ANSI。
ANSI 这里并不是严格的,是ANSI的拓展,指的是本地的编码,如中文就是GB2312