今天在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);
}
第三篇文章哈哈哈哈
人生是一场规模庞大的摸彩游戏,只有中奖的彩票展现在我们眼前。——《纸牌的秘密》
给我点十个赞我就买杯可乐庆祝下
网友评论