gb2312 转 utf-8

文章转载请注明出处:作者chinahaerbin的专栏(http://blog.csdn.net/chinahaerbin/article/details/39506415)
  cocos2dx支持中文显示,只要将中文字符转换成UTF-8字符集就可以正常显示,不过在实践上还是会出现很多问题会困扰开发者。

通常来说,目前的解决方案有以下几种:
- 1、把代码文件(.h/.cpp/.lua等)的文件编码格式改成UTF-8格式即可,这对于单机游戏来说是很好的解决方案。但是对于服务器传过来的文字则无能为力。
- 2、使用iconv库来做转换,使用接口比较简单,win32版本也能直接用上,但是在安卓上面就需要自己编译整合iconv的源码,没做过的有一些难度。
- 3、自立更生,自己写代码来实现。

  本文主要讲第三种方案,第二种方案其实也不错,但是更折腾一点,以后有时间在来折腾。自己写转utf-8的接口,主要需要考虑以下几个问题。主要都是跨平台的问题。

Windows 平台

  在win32下面,很简单也很容易实现,因为win32API已经帮我们提供了相关的接口(WideCharToMultiByte /MultiByteToWideChar等),只需要稍微处理一下即可。相关代码如下:

const char* gb23122utf8(const char* gb2312)        
{      
    int len = MultiByteToWideChar(0, 0, gb2312, -1, NULL, 0);        
    wchar_t* wstr = new wchar_t[len+1];        
    memset(wstr, 0, len+1);        
    MultiByteToWideChar(0, 0, gb2312, -1, wstr, len);        
    len = WideCharToMultiByte(65001, 0, wstr, -1, NULL, 0, NULL, NULL);        
    char* str = new char[len+1];    
    memset(str, 0, len+1);        
    WideCharToMultiByte(65001, 0, wstr, -1, str, len, NULL, NULL);        
    if(wstr) delete[] wstr;        
    return str;    
} 

Android 平台

  在安卓平台,就稍微麻烦一点。首先考虑的是,c语言有和win32接口相似的接口(mbstowcs/wcstombs等)。按这种方案,需要使用setlocale这个接口。经过测试发现,这个接口在windows和linux都有效,能正确转成utf-8码,但是在安卓上这个接口无效,始终返回NULL,所以不能使用mbstowcs/wcstombs。
  后来辗转查了一些资料,决定使用icu库,这个库在大部分安卓机器上都有,只是版本不一样,但是还是能够正确转,姑且暂时使用这种苟且的方案吧,以后再使用高大上的方案。具体代码如下:
  首先是需要找到icu库中的接口函数地址:

#include <dlfcn.h>    
void (*ucnv_convert)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*) = 0;    
bool openIcuuc()    
{    
    void* libFile = dlopen("/system/lib/libicuuc.so", RTLD_LAZY);     
    if (libFile)    
    {    
        ucnv_convert = (void (*)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*))dlsym(libFile, "ucnv_convert_3_8");    

        int index = 0;    
        char fun_name[64];    
        while (ucnv_convert == NULL)    
        {    
            sprintf(fun_name, "ucnv_convert_4%d", index++);    
            ucnv_convert = (void (*)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*))dlsym(libFile, fun_name);    
            if (ucnv_convert)     
                return true;                    
            if (++index > 11)     
                break;    
        }    
        dlclose(libFile);    
    }    
    return false;    
}     

  其次,就是转换函数代码如下:

const char* gb23122utf8(const char * gb2312)    
{    
    if (ucnv_convert == NULL)    
    {    
        openIcuuc();    
    }           
    if (ucnv_convert)    
    {    
        int err_code = 0;    
        int len = strlen(gb2312);    
        char* str = new char[len * 2 + 10];        
        memset(str, 0, len * 2 + 10);    
        ucnv_convert("utf-8", "gb2312", str, len * 2 + 10, gb2312, len, &err_code);    
        if (err_code == 0)    
        {    
            return str;    
        }    
    }    
    char test[256] = "gb23122utf8 error";    
    char* str = new char[30];     
    strcpy(str, test);    
    return str;    
}  

  好了,这就大功告成了,在几台安卓机上测试都OK,但是在模拟器上失败,可能是缺少库的问题。
  当然如果有需要可以把这个接口暴露给lua使用:

static int luaA_Strg2u(lua_State *L)    
{    
    const char* gb2312 = luaL_checkstring(L, 1);    
    const char* utf8 = gb23122utf8(gb2312);    
    lua_pushstring(L, utf8);    
    delete [] utf8;    
    return 1;    
}    

void registerLuaFunction(lua_State* luaState)    
{    
    lua_register(luaState, "strg2u", luaA_Strg2u);      
    tolua_api4lua_open(luaState);    
} 

最后把我封装的文件分享给大家吧!
文件名:GB23122Utf8.h

#ifndef __GB23122Utf8_H_  
#define __GB23122Utf8_H_  

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)  
    const char* gb23122utf8(const char* gb2312)      
    {    
        int len = MultiByteToWideChar(0, 0, gb2312, -1, NULL, 0);      
        wchar_t* wstr = new wchar_t[len+1];      
        memset(wstr, 0, len+1);      
        MultiByteToWideChar(0, 0, gb2312, -1, wstr, len);      
        len = WideCharToMultiByte(65001, 0, wstr, -1, NULL, 0, NULL, NULL);      
        char* str = new char[len+1];  
        memset(str, 0, len+1);      
        WideCharToMultiByte(65001, 0, wstr, -1, str, len, NULL, NULL);      
        if(wstr) delete[] wstr;      
        return str;  
    }    
#endif  
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
#include <dlfcn.h>  

    void (*ucnv_convert)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*) = 0;  

    bool openIcuuc()  
    {  
        void* libFile = dlopen("/system/lib/libicuuc.so", RTLD_LAZY);   
        if (libFile)  
        {  
            ucnv_convert = (void (*)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*))dlsym(libFile, "ucnv_convert_3_8");  

            int index = 0;  
            char fun_name[64];  
            while (ucnv_convert == NULL)  
            {  
                sprintf(fun_name, "ucnv_convert_4%d", index++);  
                ucnv_convert = (void (*)(const char *, const char *, char * , int32_t , const char *, int32_t,int32_t*))dlsym(libFile, fun_name);  
                if (ucnv_convert)   
                    return true;                  
                if (++index > 11)   
                    break;  
            }  
            dlclose(libFile);  
        }  
        return false;  
    }   
    const char* gb23122utf8(const char * gb2312)  
    {  
        if (ucnv_convert == NULL)  
        {  
            openIcuuc();  
        }         
        if (ucnv_convert)  
        {  
            int err_code = 0;  
            int len = strlen(gb2312);  
            char* str = new char[len * 2 + 10];      
            memset(str, 0, len * 2 + 10);  
            ucnv_convert("utf-8", "gb2312", str, len * 2 + 10, gb2312, len, &err_code);  
            if (err_code == 0)  
            {  
                return str;  
            }  
        }  
        char test[256] = "gb23122utf8 error";  
        char* str = new char[30];   
        strcpy(str, test);  
        return str;  
    }  
#endif  
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
    const char* gb23122utf8(const char * gb2312)  
    {  
        return gb2312;   
    }  
#endif  

#endif //__GB23122Utf8_H_  

Linux 平台

用C语言读取网页数据的时候,网页的编码有可能是GBK编码

Connection: Keep-Alive
Content-Type: application/x-javascript; charset=GBK

如果终端显示设置的是utf-8编码,当我们用printf打印的时候就会乱码。有两种方式解决这个问题:

  • 1、修改终端显示设置,将原来的utf-8改成GBK显示
  • 2、将获取到的GBK编码的数据转换成utf-8格式
#include <iconv.h>

int code_convert(char *from_charset,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)
        return -1;
    memset(outbuf,0,outlen);
    if (iconv(cd,pin,&inlen,pout,&outlen) == -1)
        return -1;
    iconv_close(cd);
    return 0;
}

int u2g(char *inbuf,int inlen,char *outbuf,size_t outlen)
{
    return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}

int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
    return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}

猜你喜欢

转载自blog.csdn.net/wanyongtai/article/details/77341012