VC++下处理UTF8编码的字符串

转载 2015年11月17日 19:42:10

在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转UTF8
void 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就占两个字节,对于只需要一个字节的字符,就会出问题。


ReactNative源码篇:代码调用

我们都知道如果需要用Java调用C/C++,需要用到Java中的JNI,但是用过JNI的同学都知道这是个繁琐且低效的调用方式,在大型工程体现的更加明显,因为我们需要将Java与C/C++的 相互访问与...
  • AllenWells
  • AllenWells
  • 2017-04-26 18:12:33
  • 669

一个Javacript callback注册与调用的例子

本文通过一个例子讲述javascript如何注册一个函数到中间件,中间件如何调用这个函数,传递相关的参数。 先创建头文件JSBaseTv.h声明一个c++的类,包含两个函数和一个变量: #in...
  • wowo1109
  • wowo1109
  • 2011-08-24 15:42:35
  • 2621

UTF-8 和 CString 互相转换

#include "stdafx.h" #include #include // for CString #include #include using namespace std; ch...
  • W_SX12553
  • W_SX12553
  • 2014-09-17 16:02:32
  • 9557

webkit开发之JS扩展篇

我们在做webkit的JS扩展时总会用到#include 在做webkit javascript扩展时,一般我们按以下流程做: 首先创建一个类 JSClassRef JSClassCreate...
  • lqrensn
  • lqrensn
  • 2012-10-25 10:01:38
  • 13761

CStdioFileEx(支持ANSI、UNICODE、UNICODE big endian、UTF-8编码的文本读取

  • 2015年06月12日 16:47
  • 8.12MB
  • 下载

vc 如何判断一个字符串是否是UTF8编码

UTF8是以8bits即1Bytes为编码的最基本单位,当然也可以有基于16bits和32bits的形式,分别称为UTF16和UTF32,但目前用得不多,而UTF8则被广泛应用在文件储存和网络传输中。...
  • xringm
  • xringm
  • 2016-09-26 11:26:00
  • 1229

javasript与c&c++的交互

相信初学javascript的工作于嵌入式系统的人,当然包括我自己,都有一个疑问,如果应用是html/css/javascrip写,而中间件是c/c++写,那么javascript与c/c++中间件A...
  • wowo1109
  • wowo1109
  • 2011-08-14 10:16:10
  • 2996

[深入ReactNative]第一篇 通讯及消息循环代码剖析

React Native 已经推出近一年时间了,近期也在研究iOS下用js写app的框架,从徘徊和犹豫中,最终还是选定React Native,她就像若隐若现的女神一样,想要下决心追到,可是不容易。要...
  • y2888886
  • y2888886
  • 2016-01-04 10:56:33
  • 1982

vc++中GB2312字符串和UTF-8之间的转换

http://www.cnblogs.com/babietongtianta/p/3143900.htm 在编程过程中需要对字符串进行不同的转换,特别是Gb2312和Utf-8直接的转换。在...
  • u014683488
  • u014683488
  • 2014-06-24 16:46:42
  • 1431

C++处理UTF8编码的字符串

在windows下打开一个记事本,保存文件,下面有四种编码选择: ①ANSI,也就是多字节字符集,在中文系统下约等于GB2312。 ②Unicode,就是UTF16 LE,小端序存储的UTF16。 ③...
  • CharlesSimonyi
  • CharlesSimonyi
  • 2013-03-26 21:57:50
  • 20483
收藏助手
不良信息举报
您举报文章:VC++下处理UTF8编码的字符串
举报原因:
原因补充:

(最多只允许输入30个字)