Linux下C语言GB2312转UTF8学习总结

来源:互联网 发布:vr眼镜淘宝购物视频 编辑:程序博客网 时间:2024/06/10 06:29
最近遇到中文字符编码转换的问题,总结一下。

关于字符编码的介绍,请参考如下帖子,写的很通俗易懂,赞一个~

http://apps.hi.baidu.com/share/detail/50707690

http://blog.csdn.net/zplove003/article/details/7090877

一、方法总结

方法一:直接使用记事本打开源码文件,在文件—>另存为里面选择编码类型为UTF8,可以直接将源文件保存为UTF8格式文件。

优点:快速方便

缺点:整个C文件都会转化为UTF8编码,在source insight中的所有中文注释全部变为乱码,感觉还是有点不太合适。如果注释都是英文的大神,可以无视~


方法二:在linux下使用iconv命令进行转换

例子:iconv -f gb2312 -t utf-8  gb2312toutf8.c> utf8.c

优缺点同方法一

方法三:直接调用linuxAPI函数iconv来实现。这个函数不仅能实现GB2312UTF8的转换,还支持其他不同的编码方式转换。

优点:可以将指定内容转换为UTF8,中文注释不会乱码

方法四:自己做一个编码转换表。通过查表的方式来实现。编码表不确定全不全,因GB2312UTF8没有算法可以直接转换,所以猜测iconv库函数的实现内部应该也是有会一张这样的表,下次找一下看下如果经常使用的话,编码表最好排序一下,使用二分法或其他查找算法来进行查找,提高效率。优点:可以将指定内容转换为UTF8,中文注释不会乱码

缺点:可能某些嵌入式系统上裁剪掉部分库函数,并不支持这个功能

二、测试代码

因编码表代码太长,所以编码表只取了几个字符做测试,比较全的编码表单独在另一篇中贴出来了,直接复制过来替换即可。另外,如果调用转换比较频繁的话,可以先排序一下,后续用二分法或者其他方法查找,效率会高一点。

http://blog.csdn.net/huangjiancald/article/details/49498129

方法三和方法四的测试代码如下:

#include <stdio.h>#include <netinet/in.h>#include <iconv.h>#include <string.h>#include <errno.h>/*********************数据结构*******************************/typedef struct GB2312ToUTF{    unsigned short GB2312_Code;    unsigned short UTF16;    unsigned char  UTF8_Byte0;    unsigned char  UTF8_Byte1;    unsigned char  UTF8_Byte2;}T_GB2312ToUTF;/*********************全局变量*******************************/static T_GB2312ToUTF T_GB2312ToUTFArray[]={    {0xC2EB,0x7801,0xE7,0xA0,0x81}, //码    {0xC2CA,0x7387,0xE7,0x8E,0x87}, //率};/*********************函数申明*******************************/int Gb2312ToUTF8ByCodeTable(unsigned char *src, unsigned char *dst);int GetUtfInfo(unsigned short usGb2312Data,T_GB2312ToUTF *pOutUtf);int code_convert(const char *from_charset,const char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen);int Gb2312ToUTF8BySysAPI(char *inbuf,size_t inlen,char *outbuf,size_t outlen);/********************************************************************函数名称: GetUtfInfo功能说明: 通过编码表,查到到对应的UTF信息输入参数:usGb2312Data: 输入的GB2312编码值                       pOutUtf        : 成功时返回对应的UTF信息,调用方保证                       分配足够内存返回值:成功:返回0,                 失败: -1********************************************************************/int GetUtfInfo(unsigned short usGb2312Data,T_GB2312ToUTF *pOutUtf){    int i=0;    int iUtfCodeTableLength =0;    if(pOutUtf ==NULL)    {        printf("int put parameter error! pOutUtf is NULL");        return -1;    }    //求出编码表的长度    iUtfCodeTableLength = sizeof(T_GB2312ToUTFArray)/sizeof(T_GB2312ToUTF);        for(i=0;i<iUtfCodeTableLength;i++)    {        if(usGb2312Data==T_GB2312ToUTFArray[i].GB2312_Code)        {            memcpy(pOutUtf,&T_GB2312ToUTFArray[i],sizeof(T_GB2312ToUTF));            break;        }    }    if(i==iUtfCodeTableLength)    {        printf("warning,not found utf info in table!usGb2312Data = %02x\n",usGb2312Data);        return -1;    }    return 0;}/********************************************************************函数名称: Gb2312ToUTF8ByCodeTable功能说明: 通过编码表,将GB2312格式字符串转化为UTF8格式字符串输入参数:src:输入原数据指针,dst:输出的UTF数据指针,                        调用方要保证dst缓存内容足够大返回值: 成功:返回UTF编码的长度;                  失败:-1;********************************************************************/int Gb2312ToUTF8ByCodeTable(unsigned char *src, unsigned char *dst){    unsigned char *pInData =NULL;    unsigned char *pOutData =NULL;    int iResult =-1;    int iUtfOutLength =0;    int iUtfCodeTableLength =0;    unsigned short usHostByteData =0; //代表主机字节序    T_GB2312ToUTF t_Gb2312ToUtfInfo;    memset(&t_Gb2312ToUtfInfo,0,sizeof(T_GB2312ToUTF));    if(src==NULL||dst==NULL)    {        printf("input parameter error!");        return -1;    }    pInData = src;    pOutData =dst;    while(*pInData!='\0')    {        //printf("pInData=%02x,iUtfOutLength=%d!\n",(int)(*pInData),iUtfOutLength);        /*低于128属于ascii编码相关的符号,保持不变*/        if(*pInData<0x80)        {            *pOutData = *pInData;            pInData++;            pOutData++;            iUtfOutLength++;        }        else if(*pInData>0xa1)        {            /*使用UE观察输入的gb中文是大端模式,所以这里要转换一下*/            usHostByteData = ntohs(*(unsigned short *)pInData);            //printf("Host Byte:%x\n",usHostByteData );            iResult=GetUtfInfo(usHostByteData,&t_Gb2312ToUtfInfo);            if(0==iResult)            {                memcpy(pOutData,&(t_Gb2312ToUtfInfo.UTF8_Byte0),3);                pInData+=2;                pOutData+=3;                iUtfOutLength+=3;            }            else            {                *pOutData = *pInData;                pInData++;                pOutData++;                iUtfOutLength++;            }        }        else        {            *pOutData = *pInData;            pInData++;            pOutData++;            iUtfOutLength++;        }     }    return iUtfOutLength;}/********************************************************************函数名称: code_convert功能说明: 通过编码表,将GB2312格式字符串转化为UTF8格式字符串输入参数:src:输入原数据指针,dst:输出的UTF数据指针,                        调用方要保证dst缓存内容足够大返回值: 成功:返回UTF编码的长度;                  失败:-1;********************************************************************/int code_convert(const char *from_charset,const char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen) {     iconv_t cd;     int rc;     char **pin = &inbuf;     char **pout = &outbuf;     cd = iconv_open(to_charset,from_charset);     if (cd==0)     {        printf("iconv_open failed,errno=%s\n", strerror(errno));        return -1;     }    memset(outbuf,0,outlen);     if (iconv(cd,pin,&inlen,pout,&outlen)==-1)     {        if(0!=cd)        {            iconv_close(cd);        }        printf("iconv failed,errno=%s\n", strerror(errno));        return -1;     }    iconv_close(cd);     return 0; } /********************************************************************函数名称: Gb2312ToUTF8BySysAPI功能说明: 通过编码表,将GB2312格式字符串转化为UTF8格式字符串输入参数:src:输入原数据指针,dst:输出的UTF数据指针,                        调用方要保证dst缓存内容足够大返回值: 成功:返回UTF编码的长度;                  失败:-1;********************************************************************/int Gb2312ToUTF8BySysAPI(char *inbuf,size_t inlen,char *outbuf,size_t outlen){    return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen); }void main(){    int iGb2312CodeLength=0;    int iUtfCodeLength=0;    char Gb2312[128]="码率:12Mbps";    //char Gb2312[128]="1112Mbps";    char ucUtfCode[256]={0};    char *p =NULL;    p=Gb2312;    iGb2312CodeLength =strlen(p);    Gb2312[iGb2312CodeLength]='\0';    printf("Gb2312 code:%s,input iGb2312CodeLength=%d\n", Gb2312,iGb2312CodeLength);    /*通过查找构建的编码表来实现转换*/    printf("use code table!\n");    iUtfCodeLength= Gb2312ToUTF8ByCodeTable((unsigned char*)Gb2312,(unsigned char*)ucUtfCode);    printf("GB2312-> UTF8:%s,output iUtfLength=%d\n", ucUtfCode,iUtfCodeLength);    memset(ucUtfCode,0,sizeof(ucUtfCode));        /*通过调用api函数来实现转换*/    printf("use sys api!\n");    Gb2312ToUTF8BySysAPI(Gb2312,(size_t)iGb2312CodeLength,ucUtfCode,(size_t)sizeof(ucUtfCode));    printf("GB2312-> UTF8:%s,output iUtfLength=%d\n", ucUtfCode,iUtfCodeLength);    printf("main excceed end!\n");    return;}

三、遇到的问题

在调用iconv函数时产生了异常错误EILSEQ,同时生成了core文件。后面检查发现是iconv函数的输入参数类型不对导致的,修改后正常~

ubuntu:~/code_test/GB2UTF8/src$ ./test

Gb2312 code:??:12Mbps, iGb2312CodeLength=11

use code table!

GB2312-> UTF8:码率:12Mbps, iUtfLength=13

use sys api!

iconv failed,errno=Invalid or incomplete multibyte or wide character

GB2312-> UTF8:码率:12Mbps, iUtfLength=13

main excceed end!

*** stack smashing detected ***: ./testterminated

Aborted (core dumped)

四、测试结果

修改后测试结果正常,如下:

ubuntu:~/code_test/GB2UTF8/src$ gcc gb2312toutf8.c -o test

ubuntu:~/code_test/GB2UTF8/src$ ./test

Gb2312 code:??:12Mbps,input iGb2312CodeLength=11

use code table!

GB2312-> UTF8:码率:12Mbps,output iUtfLength=13

use sys api!

GB2312-> UTF8:码率:12Mbps,output iUtfLength=13

main excceed end!

1 0