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

在windows下打开一个记事本,保存文件,下面有四种编码选择:

①ANSI,也就是多字节字符集,在中文系统下约等于GB2312。

②Unicode,就是UTF16 LE,小端序存储的UTF16。

③Unicode big endian ,就是UTF16 BE,大端序存储的UTF16

④UTF8,网页上很多都是用UTF8,UTF8用1-4个字节来编码所有的字符,英文只需要1个 字节,中文需要3-4个字节。比起UTF16来说,UTF8这样可以尽可能的节省网络带宽,因为在网络上传输的字符,大部分以英文为主。UTF16至少是2个字节,部分字符4个字节。

如果我们写一个VC程序,从Web上获取到了网页内容,这些数据的编码大多是UTF8的,获取到我们VC程序中的char字符数组中时就会发现,英文可以正常显示,中文全部乱码了。因为VC把char数组中的字符串当做多字节字符集来处理。为了能正常显示UTF8编码的字符串,我们需要进行一些转换。将其转换为多字节字符集的字符串(ANSI),或是转换为宽字节字符串(UTF16)。

我们可以使用Windows API中的MultiByteToWideChar和WideCharToMultiByte来进行转换。示例代码如下:

std::wstring UTF8_To_UTF16(const std::string &source)
{
	unsigned long len = ::MultiByteToWideChar(CP_UTF8, NULL, source.c_str(), -1, NULL, NULL);
	if (len == 0)
		return std::wstring();
	wchar_t *buffer = new wchar_t[len];
	::MultiByteToWideChar(CP_UTF8, NULL, source.c_str(), -1, buffer, len);
	
	std::wstring dest(buffer);
	delete [] buffer;
	return dest;
}

std::string UTF16_To_UTF8(const std::wstring &source)
{
	unsigned long len = ::WideCharToMultiByte(CP_UTF8, NULL, source.c_str(), -1, NULL, NULL, NULL, NULL);
	if (len == 0)
		return std::string();
	char *buffer = new char[len];
	::WideCharToMultiByte(CP_UTF8, NULL, source.c_str(), -1, buffer, len, NULL, NULL);
	
	std::string dest(buffer);
	delete [] buffer;
	return dest;
}


std::wstring GBK_To_UTF16(const std::string &source)
{
	enum {GB2312 = 936};
	
	unsigned long len = ::MultiByteToWideChar(GB2312, NULL, source.c_str(), -1, NULL, NULL);
	if (len == 0)
		return std::wstring();
	wchar_t *buffer = new wchar_t[len];
	::MultiByteToWideChar(GB2312, NULL, source.c_str(), -1, buffer, len);
	
	std::wstring dest(buffer);
	delete [] buffer;
	return dest;
}

std::string UTF16_To_GBK(const std::wstring &source)
{
	enum {GB2312 = 936};
	
	unsigned long len = ::WideCharToMultiByte(GB2312, NULL, source.c_str(), -1, NULL, NULL, NULL, NULL);
	if (len == 0)
		return std::string();
	char *buffer = new char[len];
	::WideCharToMultiByte(GB2312, NULL, source.c_str(), -1, buffer, len, NULL, NULL);
	
	std::string dest(buffer);
	delete [] buffer;
	return dest;
}

std::string GBK_To_UTF8(const std::string &source)
{
	enum {GB2312 = 936};
	
	unsigned long len = ::MultiByteToWideChar(GB2312, NULL, source.c_str(), -1, NULL, NULL);
	if (len == 0)
		return std::string();
	wchar_t *wide_char_buffer = new wchar_t[len];
	::MultiByteToWideChar(GB2312, NULL, source.c_str(), -1, wide_char_buffer, len);
	
	len = ::WideCharToMultiByte(CP_UTF8, NULL, wide_char_buffer, -1, NULL, NULL, NULL, NULL);
	if (len == 0)
	{
		delete [] wide_char_buffer;
		return std::string();
	}
	char *multi_byte_buffer = new char[len];
	::WideCharToMultiByte(CP_UTF8, NULL, wide_char_buffer, -1, multi_byte_buffer, len, NULL, NULL);
	
	std::string dest(multi_byte_buffer);
	delete [] wide_char_buffer;
	delete [] multi_byte_buffer;
	return dest;
}

std::string UTF8_To_GBK(const std::string &source)
{
	enum {GB2312 = 936};

	unsigned long len = ::MultiByteToWideChar(CP_UTF8, NULL, source.c_str(), -1, NULL, NULL);
	if (len == 0)
		return std::string();
	wchar_t *wide_char_buffer = new wchar_t[len];
	::MultiByteToWideChar(CP_UTF8, NULL, source.c_str(), -1, wide_char_buffer, len);
	
	len = ::WideCharToMultiByte(GB2312, NULL, wide_char_buffer, -1, NULL, NULL, NULL, NULL);
	if (len == 0)
	{
		delete [] wide_char_buffer;
		return std::string();
	}
	char *multi_byte_buffer = new char[len];
	::WideCharToMultiByte(GB2312, NULL, wide_char_buffer, -1, multi_byte_buffer, len, NULL, NULL);
	
	std::string dest(multi_byte_buffer);
	delete [] wide_char_buffer;
	delete [] multi_byte_buffer;
	return dest;
}

涵盖了三种常见字符集字符串的相互转换,如果转换失败会返回一个空字符串,失败的情况很罕见,我目前还没遇到过。

实际上C++标准库也提供了一些转换方法,不过标准库只提供了UTF8与UTF16之间的转换,使用标准库可以跨平台使用,但是需要C++11的支持。示例代码如下:

#include <locale>
#include <codecvt>

std::wstring UTF8_To_UTF16(const std::string &source)
{
	try
	{
		static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt;
		return cvt.from_bytes(source);
	}
	catch (std::range_error &)
	{
		return std::wstring();
	}
}

std::string UTF16_To_UTF8(const std::wstring &source)
{
	try
	{
		static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt;
		return cvt.to_bytes(source);
	}
	catch (std::range_error &)
	{
		return std::string();
	}
}


另外,如果需要在GCC上实现的话,可以用标准库中的mbstowcs代替MultiByteToWideChar,用wcstombs代替WideCharToMultiByte,当然用iconv更方便。

在VC上也可以使用mbstowcs和wcstombs,因为其内部就是用MultiByteToWideChar和WideCharToMultiByte实现的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值