多字节与宽字符串的相互转换

1.多字节字符串与宽字符串

说到多字节字符串与宽字符串,不得不说一下多字节字符与宽字符。多字节字符实际上是由多个字节来表示一个字符,在各个国家和地区采用不同的编码方案,不同编码方案字符码值是不同的,比如常见的中国大陆的GBK和GB18030、台湾同胞的Big5h,以及国际通过的UTF8编码等。宽字符指的是由统一码联盟制定的Unicode编码方案收录的字符,使用4个字节来表示一个字符。关于字符编码可参见博文精述字符编码

2.多字节与宽字符串的相互转化

使用C/C++实现多字节字符串与宽字符串的相互转换,需要使用函数C标准库函数mbstowcs和wcstombs。

//将多字节编码转换为宽字节编码
size_t mbstowcs (wchar_t* dest, const char* src, size_t max);

//将宽字节编码转换为多字节编码
size_t wcstombs (char* dest, const wchar_t* src, size_t max);

这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。Linux下输入命名locale -a查看系统支持的编码类型。

andy@andy-linux:~$ locale -a
c
en_ag
en_au.utf8
en_bw.utf8
en_ca.utf8
en_dk.utf8
en_gb.utf8
en_hk.utf8
en_ie.utf8
en_in
en_ng
en_nz.utf8
en_ph.utf8
en_sg.utf8
en_us.utf8
en_za.utf8
en_zw.utf8
posix
zh_cn.gb18030
zh_cn.gbk
zh_cn.utf8
zh_hk.utf8
zh_sg.utf8
zh_tw.utf8

talk is cheap,show me the code!下面给出实现。

#include <locale.h>
#include <stdlib.h>

/********************************************
*@brief:不同编码字符串转Unicode
*@pram:cpMbs:多字节字符串;wcpWcs:宽字符串;wcsBuffLen:宽字符串缓冲区大小(单位宽字符);dEncodeType:多字节字符串编码类型,0:GBK,1:UTF8
*@ret:-1:出错;>=0:转换成功的字符个数
*@birth:created by dablelv on 20170804
*@revision:
********************************************/
int mbs2wcs(const char* cpMbs,wchar_t* wcpWcs,int wcsBuffLen,int dEncodeType)
{
    if(NULL==cpMbs||0==strlen(cpMbs)) return 0;

    //GBK转Unicode
    if(0==dEncodeType)
    {
        if(NULL==setlocale(LC_ALL,"zh_CN.gbk"))     //设置转换为unicode前的编码为gbk编码        
            return -1;
    }
    //UTF8转Unicode
    if(1==dEncodeType)
    {
        if(NULL==setlocale(LC_ALL,"zh_CN.utf8"))    //设置转换为unicode前的编码为utf8编码
            return -1;
    }

    int unicodeCNum=mbstowcs(NULL,cpMbs,0);             //计算待转换的字符数
    if(unicodeCNum<=0||unicodeCNum>=wcsBuffLen)         //转换失败或宽字符串缓冲区大小不足
    {
        return -1;
    }
    unicodeCNum=mbstowcs(wcpWcs,cpMbs,wcsBuffLen-1);    //进行转换,wcsBuffLen-1表示最大待转换的宽字符数,即宽字符串缓冲区大小
    return unicodeCNum;
}

/********************************************
*@brief:Unicode转指定编码字符串
*@pram:wcpWcs:宽字符串;cpMbs:多字节字符串缓冲区;dBuffLen:多字节字符串缓冲区大小(单位字节);dEncodeType:多字节字符串编码类型,0:GBK,1:UTF8
*@ret:-1:出错;>=0:转换成功的字节个数
*@birth:created by dablelv on 20180114
*@revision:
********************************************/
int wcs2mbs(const wchar_t* wcpWcs,char* cpMbs,int dBuffLen,int dEncodeType)
{
    if(wcpWcs==NULL || wcslen(wcpWcs)==0)
    {
        return 0;
    }

    //Unicode转GBK
    if(0==dEncodeType)
    {
        if(NULL==setlocale(LC_ALL,"zh_CN.gbk"))     //设置目标字符串编码为gbk编码
            return -1;
    }
    //Unicode转UTF8
    if(1==dEncodeType)
    {
        if(NULL==setlocale(LC_ALL,"zh_CN.utf8"))    //设置目标字符串编码为utf8编码
            return -1;
    }

    int dResultByteNum=wcstombs(NULL,wcpWcs,0);     //计算待转换的字节数
    if(dResultByteNum<=0 || dResultByteNum>=dBuffLen)
    {
        return -1;                                  //转换失败或多字节字符串缓冲区大小不足
    }
    wcstombs(cpMbs,wcpWcs,dBuffLen-1);
    return dResultByteNum;
}

3.测试

代码文件使用UTF8编码,代码如下:

int main(int argc,char* argv[])
{
    char* cpMbs="I believe 中国民族将实现伟大复兴";
    wchar_t* wcpWcs=L"I believe 中国民族将实现伟大复兴";
    char cBuff[1024]={'\0'};
    wchar_t wcBuff[1024]={L'\0'};

    //将UTF8编码多字节字符串转换为Unicode字符串
    int ret=mbs2wcs(cpMbs,wcBuff,1024,1);
    //转换后字符串与字符串长度
    printf("返回值:%d,字符数:%d,宽字符串:%S\n",ret,wcslen(wcBuff),wcBuff);    //printf使用%ls也可以输出宽字符串

    //Unicode字符串转换为UTF8编码多字节字符串
    ret=wcs2mbs(wcpWcs,cBuff,1024,1);
    //转换后字符串与字符串字节数
    printf("返回值:%d,字符串字节数:%d,字符串:%s\n",ret,strlen(cBuff),cBuff);
}

测试输出结果为:

返回值:21,字符数:21,宽字符串:I believe 中国民族将实现伟大复兴
返回值:43,字符串字节数:43,字符串:I believe 中国民族将实现伟大复兴

注意:请不要将printf与wprintf同时使用,否则会出现后者无法输出的奇怪现象。该现象的解释与解决办法参见博文printf()详解之终极无惑


[1]Linux C++ gbk转为utf-8 [2]精述字符编码

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏pangguoming

java正则校验,密码必须由字母和数字组成

一个匹配数字和字母密码的正则表达式 2011 年 12 月 14 日 | Filed under: 正则表达式 and tagged with: 密码 , ...

5406
来自专栏王亚昌的专栏

类模板学习总结

1.类模板就是给普通的类加上一个参数,参数可以是未知数据类型标识(如int, string,char, class等),也可以是已知数据类型的值,在下面的第二个...

972
来自专栏Python小屋

1000道Python题库系列分享四(40道)

热烈庆祝2018年2月董付国老师《Python程序设计(第2版)》出版18个月第5次印刷,《Python可以这样学》出版12个月第5次印刷,系列教材《Pytho...

8877
来自专栏一枝花算不算浪漫

[C#基础]基础知识一: 面向对象的基本知识.

42617
来自专栏Java帮帮-微信公众号-技术文章全总结

第十三天 面向对象-final static 匿名对象内部类包代码块【悟空教程】

1434
来自专栏Android开发指南

1:基本概念

2897
来自专栏nnngu

Java中的String类能否被继承?为什么?

不能被继承,因为String类有final修饰符,而final修饰的类是不能被继承的。 Java对String类的定义: public final class ...

4316
来自专栏超然的博客

ECMAScript 6 笔记(一)

       1996年11月,JavaScript的创造者Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国...

1073
来自专栏WindCoder

Python第五周学习笔记

发现之前并没有字符串相关的介绍,再者此次做的有点多,就整理一下发出来算了。此处的例子将代码和运行结果写在了一起,并未分开,细心看下也是可以看懂的,一般不存在 >...

731
来自专栏代码世界

Python基础数据类型之int、bool、str

数据类型:int  bool  str  list  元祖  dict  集合 int:整数型,用于各种数学运算。 bool:只有两种,True和False,用...

3386

扫码关注云+社区

领取腾讯云代金券