utf-8编码转gbk(C语言实现, 解决控制台输出utf-8乱

2018-02-06  本文已影响0人  zzkdev

今天在windows控制台上打印utf-8字符时出现了乱码,然后就折腾了一下发现在简体中文版上的windows默认的代码页是936(gbk编码),在控制台上输入chcp 65001解决之(65001是UTF-8代码页编号),但是我这么爱钻研(瞎折腾)怎么可能就这么完事了呢,就尝试了下用C语言实现utf-8转化成gbk编码(还顺便学习了下几种编码),下面是解决方法。

嗯。。还有我学习时看的一个资料,介绍编码知识的

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

解决方法

1.使用代码更改活动代码页

system("chcp 65001");

也可以使用windows的一个API(设置输出代码页),效果一样

SetConsoleOutputCP(65001);

还有另外一个API是SetConsoleCP(),这个API设置的是输入代码页,在输出时并不起作用

C语言标准里面还提供了一个函数来设置代码页Setlocale(),不过没有测试过

2.将utf-8转换成gbk编码

原理是利用windows的两个API,将UTF-8转成unicode编码,再转成gbk编码

下面是对两个函数的介绍

函数原型

int MultiByteToWideChar(

UINT CodePage,

DWORD dwFlags,

LPCSTR lpMultiByteStr,

int cchMultiByte,

LPWSTR lpWideCharStr,

int cchWideChar);

函数功能 

该函数映射一个字符串到一个宽字符(unicode)的字符串。由该函数映射的字符串没必要是多字节字符组。

参数

CodePage:指定执行转换的代码页,这个参数可以为系统已安装或有效的任何代码页所给定的值。我们用到的是下面两个值(当然你也可以指定别的值):

CP_ACP:ANSI代码页(简体中文Windows操作系统中,ANSI 编码代表 GBK 编码)

CP_UTF8:使用UTF-8转换

dwFlags: 指定如何处理没有转换的字符,但不设此参数函数会运行的更快一些,我都是把它设为0。 可设的值如下表所示:

WC_NO_BEST_FIT_CHARS

把不能直接转换成相应多字节字符的Unicode字符转换成lpDefaultChar指定的默认字符。也就是说,如果把Unicode转换成多字节字符,然后再转换回来,你并不一定得到相同的Unicode字符,因为这期间可能使用了默认字符。此选项可以单独使用,也可以和其他选项一起使用。

WC_COMPOSITECHECK

把合成字符转换成预制的字符。它可以与后三个选项中的任何一个组合使用,如果没有与他们中的任何一个组合,则与选项WC_SEPCHARS相同。

WC_ERR_INVALID_CHARS

此选项会致使函数遇到无效字符时失败返回,并且GetLastError会返回错误码ERROR_NO_UNICODE_TRANSLATION。否则函数会自动丢弃非法字符。此选项只能用于UTF8。

WC_DISCARDNS   

转换时丢弃不占空间的字符,与WC_COMPOSITECHECK 一起使用

WC_SEPCHARS

转换时产生单独的字符,此是默认转换选项,WC_COMPOSITECHECK一起使用

WC_DEFAULTCHAR

转换时使用默认字符代替例外的字符,(最常见的如’?’),与WC_COMPOSITECHECK一起使用。

对于下列代码页,dwFlags必须为0,否则函数返回错误码ERROR_INVALID_FLAGS。 50220 50221 50222 50225 50227 50229 52936 54936 57002到57011 65000(UTF7) 42(Symbol)

对于UTF8,dwFlags必须为0或WC_ERR_INVALID_CHARS,否则函数都将失败返回并设置错误码ERROR_INVALID_FLAGS,你可以调用GetLastError获得。

lpMultiByteStr:指向将被转换字符串的字符。

cchMultiByte:指定由参数lpMultiByteStr指向的字符串中字节的个数。如果这个值为-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度。

lpWideCharStr:指向接收被转换字符串的缓冲区。

cchWideChar:指定由参数lpWideCharStr指向的缓冲区的字节个数。若此值为零,函数返回缓冲区所必需的宽字符数,在这种情况下,lpWideCharStr中的缓冲区不被使用。

返回值:如果函数运行成功,并且cchWideChar不为零,返回值是由lpWideCharStr指向的缓冲区中写入的宽字符数;如果函数运行成功,并且cchMultiByte为零,返回值是接收到待转换字符串的缓冲区所需求的宽字符数大小。如果函数运行失败,返回值为零。

函数原型

int WideCharToMultiByte(

UINT CodePage,

DWORD dwFlags,

LPCWSTR lpWideCharStr,

int cchWideChar,

LPSTR lpMultiByteStr,

int cbMultiByte,

LPCSTR lpDefaultChar,

LPBOOL lpUsedDefaultChar);

函数功能 

此函数把宽字符串转换成指定的新的字符串,如ANSI,UTF8等,新字符串不必是多字节字符集。 

参数

lpWideCharStr : 待转换的宽字符串。

cchWideChar : 待转换宽字符串的长度,-1表示转换到字符串结尾。

lpMultiByteStr : 接收转换后输出新串的缓冲区。

cbMultiByte :输出缓冲区大小,如果为0,lpMultiByteStr将被忽略,函数将返回所需缓冲区大小而不使用lpMultiByteStr。

lpDefaultChar : 指向字符的指针, 在指定编码里找不到相应字符时使用此字符作为默认字符代替。如果为NULL则使用系统默认字符。对于要求此参数为NULL的dwFlags而使用此参数,函数将失败返回并设置错误码ERROR_INVALID_PARAMETER。

lpUsedDefaultChar :开关变量的指针,用以表明是否使用过默认字符。对于要求此参数为NULL的dwFlags而使用此参数,函数将失败返回并设置错误码ERROR_INVALID_PARAMETER。lpDefaultChar和lpUsedDefaultChar都设为NULL,函数会更快一些。

返回值 :如果函数成功,且cbMultiByte非0,返回写入lpMultiByteStr的字节数(包括字符串结尾的null);cbMultiByte为0,则返回转换所需字节数。函数失败,返回0。


下面是简单的函数实现

void utf8ToGbk(char *utf8String, char *gbkString)

{

wchar_t *unicodeStr = NULL;

int nRetLen = 0;

nRetLen = MultiByteToWideChar(CP_UTF8, 0, utf8String, -1, NULL, 0);

//求需求的宽字符数大小

unicodeStr = (wchar_t *)malloc(nRetLen * sizeof(wchar_t));

nRetLen = MultiByteToWideChar(CP_UTF8, 0, utf8String, -1, unicodeStr, nRetLen);

//将utf-8编码转换成unicode编码

nRetLen = WideCharToMultiByte(CP_ACP, 0, unicodeStr, -1, NULL, 0, NULL, 0);

//求转换所需字节数

nRetLen = WideCharToMultiByte(CP_ACP, 0, unicodeStr, -1, gbkString, nRetLen, NULL, 0);

//unicode编码转换成gbk编码

free(unicodeStr);

}


第三篇文章哈哈哈哈


人生是一场规模庞大的摸彩游戏,只有中奖的彩票展现在我们眼前。——《纸牌的秘密》


给我点十个赞我就买杯可乐庆祝下

上一篇下一篇

猜你喜欢

热点阅读