GBK(GB2312)向UTF-8的编码转换 -- C++

转载 2011年10月14日 21:55:02


GBK(GB2312)向UTF-8的编码转换 -- C++
2008年05月30日 星期五 17:24

最近做一个IE插件,要从网页中取得文字,编码到一个URL中去。在前一篇文章“中文URL编码”中,粗略地介绍了URL编码的规则,以及中文URL编码的过程,但在如何将GBK或者GB2312编码的汉字转换到UTF-8编码仍然是一个问题。编码是一个很复杂的问题,我也了解甚少,这里只是写写我的经验,欢迎补充和指正。

在PHP、.NET中,编码的转换都比较容易。ATL中有一些宏是用来做编码转换的,我没试过,而且我更愿意用后面所讲的方法。

在COM编程中,字符串多存储在BSTR结构中。网上许多文章都说这个数据结构中存储的就是Unicode,我就试了好多次从Unicode转UTF-8,未遂。在Debug的时候,含有中文字符串的BSTR能够正常显示,说明它的编码应该是GBK.

如何从GBK转换到UTF-8呢?libiconv应该可以做到,然而我使用它的Windows port后,可以编译、注册COM组件,就是工具栏出不来了,于是放弃。上网搜索,得到一个被广泛转载的CChineseCode类。然而它仅仅针对汉字(每个汉字在UTF-8编码中占3个字节),如果字符串中有英文,就有麻烦了,因为英文在UTF-8编码中只有一个字节。另外有的字符会占用更多的字节。所以这个类并不适用。

正确的方法是用Win32 API的MultiByteToWideCharWideCharToMultiByte两个函数,Wide character指的就是Unicode. GBK和UTF-8之间的转换,需要用Unicode作为桥梁(在这种方法里)。比如我们要转换这样一个字符串”编码 - Google 搜索”。

从GBK向Unicode转换

该字符串在BSTR类型的变量in中存储,首先将其转换为普通的字符串:

char *lpszText = _com_util::ConvertBSTRToString(in);

此时,如果用strlen函数取得lpszText的长度,则为18,4个汉字,每个占两个字节,另外有10个英文字符。所以说GBK/GB2312是MultiByte而不是WideChar. 并且有lpszText[0] == 0xb1 && lpszText[1] == 0xe0,在微软Windows Codepage 936这一页上查到果然是“编”字,更坚定了我们认为它是GBK的信心。

转换到Unicode所用的函数是MultiByteToWideChar,第一个参数是MultiByte的Code page,如果确定是GBK,就可以使用936. 我考虑它应该是与系统有关的(比如日语系统上应该是932),所以使用CP_ACP,系统所用的Codepage.

先通过将cchWideChar参数设置为0,取得转换后需要的空间大小,然后分配空间,再做实际的转换(转换时cbMultiByte为-1表示要转换的字符串以0结尾)。代码如下:

int wLen = MultiByteToWideChar(CP_ACP, 0, lpszText, -1, NULL, 0);
LPWSTR wStr = (LPWSTR)CoTaskMemAlloc(wLen * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpszText, -1, wStr, wLen);

wLen是15,注意是指宽字符的个数,很贴心,14个字符,加上末尾的结束符。分配空间的时候也要注意,不是15个字节,而应该分配30个字节。这些在MSDN中都有说明,仔细看cchWideChar参数的介绍。最后一行代码执行后,wStr中就是这些汉字的Unicode了,查看一下,wStr[0] == 0×7f16,刚才在微软Windows Codepage 936查找时,“编”字的下面标明7f16,就是它的Unicode编码,说明一切正常。

从Unicode向UTF-8转换

转换到Unicode后,就可以使用WideCharToMultiByte函数将其转换到UTF-8编码,这次的code page要用CP_UTF8. 和前面的转换一样,先计算所需要的空间大小并分配,再做实际转换。

int aLen = WideCharToMultiByte(CP_UTF8, 0, wStr, -1, NULL, 0, NULL, NULL);
char* converted = (char*)CoTaskMemAlloc(aLen);
WideCharToMultiByte(CP_UTF8, 0, wStr, -1, converted, aLen, NULL, NULL);

aLen为23,因为4个汉字,每个占3个字节,加上10个英文字符(每个占1字节),再加末尾的’\0′,正好是23. 现在converted里就是字符串”编码 - Google 搜索”的UTF-8编码。converted[0] == 0xe7 && converted[1] == 0xbc,正是“编”字的UTF-8编码。

好了,现在终于得到了中英文混合字符串的UTF-8字节序列,可以进行URL编码(percent encoding)了。

如果你也看了CChineseCode类的代码,就会奇怪既然作者知道用WideCharToMultiByte做GB2312到Unicode的转换,为什么在UnicodeToUTF_8函数中要舍近求远呢?

企业微信支付C#版_企业红包+向员工付款+向员工收款

“企业微信支付”系列课程讲解企业微信支付的全部知识点“企业红包”;“向员工付款”;“向员工收款”。课程分JAVA版、C#版,提供源程序,有技术问题可以指导。 购课咨询,技术指导,qq2326321088
  • 2017年09月18日 10:55

C/C++,字符串的UTF-8与GBK(或GB2312)编码转换

写代码时经常会遇到各种编码转换问题,因此记录下来以便日后对各种平台下不同编码转换作整理。 C/C++: GBK(或GB2312)转UTF-8实现:...
  • xiaohu_2012
  • xiaohu_2012
  • 2013-11-07 18:17:52
  • 10216

C++中GB2312字符串和UTF-8之间的转换 从CString 的转换

在编程过程中需要对字符串进行不同的转换,特别是Gb2312和Utf-8直接的转换。在几个开源的魔兽私服中,很多都是老外开发的,而暴雪为了能 够兼容世界上的各个字符集也使用了UTF-8。在中国使用VS(...
  • liu0115
  • liu0115
  • 2015-08-23 10:27:57
  • 1311

在JSP中 中文的编码详解 gb2312 GBK UTF-8

1 设置workspace 编码:window-->General-->Workspace-->设置 2 在文件右键选Properties-->Resource:修改text file encodi...
  • donghedonghe
  • donghedonghe
  • 2012-04-24 09:27:55
  • 2474

C# UTF-8与GB2312编码的相互转化

1、首先引入命名空间:
  • u014076894
  • u014076894
  • 2014-10-22 20:59:16
  • 13891

MD5 编码 转换

 编码MD5转换相关问题! public static void main(String[] args) throws UnsupportedEncodingException { // Stri...
  • evane1890
  • evane1890
  • 2011-04-06 14:00:00
  • 2170

文本文件编码转换工具 gbk utf8 gb2312

  • 2010年01月26日 18:27
  • 42KB
  • 下载

多线程批量转换文件编码, 从GBK, GB2312编码转换到UTF-8编码(Python)

# description: 1. 批量转换文件编码,从GBK GB2312编码转换到UTF-8编码 # 2. 支持指定目录下所有的文件的转换,包括子目录中的文件 # ...
  • vieri_ch
  • vieri_ch
  • 2015-04-02 14:28:21
  • 4287

GBK、UTF-8编码转换工具

  • 2014年06月01日 23:53
  • 30KB
  • 下载

用JavaScript实现的将GB2312转换为UTF-8编码

function gb2utf8(data){    var glbEncode = [];    gb2utf8_data = data;    execScript("gb2utf8_data =...
  • hb_cattle
  • hb_cattle
  • 2007-03-24 20:12:00
  • 1790
收藏助手
不良信息举报
您举报文章:GBK(GB2312)向UTF-8的编码转换 -- C++
举报原因:
原因补充:

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