VC++下处理UTF8编码的字符串
2015-11-17 19:42
274 查看
在windows下打开一个记事本,保存文件,下面有四种编码选择。ANSI,也就是多字节字符集,在VC中也就是CHAR(char)字符串。Unicode,就是UTF16,在VC中也就是WCHAR(wchar_t)字符串。Unicode big endian ,就是UTF32,这种编码用的比较少。UTF8,网页上几乎都是用UTF8,UTF8用1-4个字节来编码所有的字符,英文只需要1个 字节,中文需要3-4个字节。比起UTF16来说,UTF8这样可以尽可能的节省网络带宽,因为在网络上传输的字符,大部分以英文为主。UTF16至少是2个字节,部分字符4个字节。如果我们写一个VC程序,从获取HTML网页数据,这些数据的编码是UTF8的,获取到我们VC程序中的CHAR字符数组中时就会发现,英文可以正常显示,中文全部乱码了。因为我们的CHAR型字符串用的是ANSI编码。要想把UTF8转换为ANSI,一般有两种方法。一种是手工写代码实现,百度上搜索可以发现很多资料,透彻了解这些字符集编码后,可以手工来实现转换,网上也有很多别人写好的转换函数。一种方法就是借助第三方函数库。由于我们在windows平台下编写程序,我们可以使用API函数来转换MultiByteToWideChar和WideCharToMultiByte。使用这个函数,我们得进行两次转换,先用MultiByteToWideChar把UTF8编码的CHAR字符串转换成WCHAR字符串,第一个参数要注明我们要转换的代码页为CP_UTF8,即UTF8的意思。然后用WideCharToMultiByte吧WCHAR字符串转换成CHAR字符串,第一个参数使用936,936代码页的意思是简体中文。有关代码页的知识可以百度百科一下。下面贴出我写的两个ANSI与UTF8互转的函数。参数为MFC中的CString字符串,如果要传入C样式的字符数组型字符串,只需稍加修改即可。//UTF8转ANSI
utf8* AnsiToUtf8(char const *szAnsi) { // ANSI => WCHAR size_t lengthAnsi = strlen(szAnsi); size_t lengthUnicode = MultiByteToWideChar(CP_ACP, 0, szAnsi, lengthAnsi, NULL, 0); if (s_wchar_buf.size() < lengthUnicode + 1) { s_wchar_buf.resize(lengthUnicode * 2); } wchar_t *szUnicode = &s_wchar_buf[0]; ::MultiByteToWideChar(CP_ACP, 0, szAnsi, lengthAnsi, szUnicode, lengthUnicode); szUnicode[lengthUnicode] = 0; // WCHAR => UTF8 size_t lengthUtf8 = ::WideCharToMultiByte(CP_UTF8, 0, szUnicode, lengthUnicode, NULL, 0, NULL, NULL); if (s_utf8_buf.size() < lengthUtf8 + 1) { s_utf8_buf.resize(lengthUtf8 * 2); } utf8 *szUtf8String = &s_utf8_buf[0]; ::WideCharToMultiByte(CP_UTF8, 0, szUnicode, lengthUnicode, (char *)szUtf8String, lengthUtf8, NULL, NULL); szUtf8String[lengthUtf8] = 0; return (utf8 *)szUtf8String; } char* Utf8ToAnsi( String u8 ) { //UTF8 => WCHAR size_t lengthUnicode = ::MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.utf8_stream_len(), NULL, NULL); if (s_wchar_buf.size() < lengthUnicode + 1) { s_wchar_buf.resize(lengthUnicode * 2); } wchar_t *szUnicode = &s_wchar_buf[0]; ::MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.utf8_stream_len(),szUnicode, lengthUnicode); szUnicode[lengthUnicode] = 0; //WCHAR => ANSI int lengthAnsi = ::WideCharToMultiByte(CP_ACP, 0, szUnicode, lengthUnicode, NULL, NULL, NULL, NULL ); if (s_ansi_buf.size() < lengthAnsi + 1) { s_ansi_buf.resize( lengthAnsi * 2 ) ; } char* szAnsi = &s_ansi_buf[0]; ::WideCharToMultiByte(CP_ACP, 0, szUnicode, lengthUnicode, szAnsi, lengthAnsi, NULL, NULL ); szAnsi[lengthAnsi] = 0; return szAnsi; }
<span style="font-family: Arial;"><pre name="code" class="cpp">//UTF8转ANSI</span>
void UTF8toANSI(CString &strUTF8){//获取转换为多字节后需要的缓冲区大小,创建多字节缓冲区UINT nLen = MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,NULL,NULL);WCHAR *wszBuffer = new WCHAR[nLen+1];nLen = MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,wszBuffer,nLen);wszBuffer[nLen] = 0;nLen = WideCharToMultiByte(936,NULL,wszBuffer,-1,NULL,NULL,NULL,NULL);CHAR *szBuffer = new CHAR[nLen+1];nLen = WideCharToMultiByte(936,NULL,wszBuffer,-1,szBuffer,nLen,NULL,NULL);szBuffer[nLen] = 0;strUTF8 = szBuffer;//清理内存delete []szBuffer;delete []wszBuffer;}
//ANSI转UTF8void ANSItoUTF8(CString &strAnsi){//获取转换为宽字节后需要的缓冲区大小,创建宽字节缓冲区,936为简体中文GB2312代码页UINT nLen = MultiByteToWideChar(936,NULL,strAnsi,-1,NULL,NULL);WCHAR *wszBuffer = new WCHAR[nLen+1];nLen = MultiByteToWideChar(936,NULL,strAnsi,-1,wszBuffer,nLen);wszBuffer[nLen] = 0;//获取转为UTF8多字节后需要的缓冲区大小,创建多字节缓冲区nLen = WideCharToMultiByte(CP_UTF8,NULL,wszBuffer,-1,NULL,NULL,NULL,NULL);CHAR *szBuffer = new CHAR[nLen+1];nLen = WideCharToMultiByte(CP_UTF8,NULL,wszBuffer,-1,szBuffer,nLen,NULL,NULL);szBuffer[nLen] = 0;strAnsi = szBuffer;//内存清理delete []wszBuffer;delete []szBuffer;}值得注意的是,UTF8编码的字符串一般要将其保存在CHAR(char)型数组里,而不保存在WCHAR(wchar_t)型数组里。为什么呢?因为UTF8编码的字符串每个字符占1-4个字节,有的字符只占1个字节,应该用CHAR型数组来保存。而WCHAR的话,一个WCHAR就占两个字节,对于只需要一个字节的字符,就会出问题。
相关文章推荐
- 回溯法-旅行售货员问题(C语言)
- C语言基础-- 内存存储
- C++模板
- C++如何将N维数组作为参数动态传给方法
- 今日学习札记——<string>模板类(11.17)
- C++上的“基础姿势”以及“特殊姿势”
- 关于C++转换函数
- c++学习 ( new, delete)
- C++模板的编译与连接
- C++ 学习
- C语言运算符优先级误解
- 编写configure.ac
- STL: reverse_iterator / iterator 关系以及 erase 相关(C++)
- 转载关于char的c语言指针问题:char **s char *a [ ] char a [ ]
- 浅析C语言编程中的数组越界问题
- 【C语言】【面试题】【笔试题】调整数组使奇数全部都位于偶数前面
- 通过一个小例子来简单理解C语言中的内存空间管理
- 对C语言编程标准以及声明的基本理解
- C++字符串转化为数字的库函数
- C++字符串类型和数字之间的转换