C++ 软件开发多国语言解决方案汇总

暂时汇总出了以下几种方法

  • 以Unicode为核心

  • 采用 GNU gettext 

  • 基于Qt的多语言开发工具:Qt Linguist 

 

以Unicode为核心


参考:http://www.ibm.com/developerworks/cn/linux/l-cn-ccppglb/

多国语言的存在,使程序员在编码处理上花费了大量时间和精力;然而各种各样的乱码问题,如 XML 格式错误、文本显示异常、解析器异常等依然层出不穷。特别的,相对于 JAVA 语言,C/C++ 在处理编码问题上有更大的困难。本文避免纠缠不同编码格式的具体异同,以 Unicode 为核心,以简体中文为例,从工程应用角度分析编码问题存在的原因,不仅提出 C/C++ 标准库编程的解决方案,更结合项目经验,总结出处理多国语言编码问题的一般思路。

问题的提出

多国语言的存在、不同语言操作系统的存在,使得针对多语言的设计颇费周章,在编码上所付出的工作量也是可观的。所谓编码的问题,归结起来,就是二进制的编码以何种编码格式进行解析的问题。特别是在硬盘文件和内存数据的相互转化、即读写过程中,如果采用了错误的编码格式,就会造成乱码。JAVA 语言在字符串、编码等处理方面给了程序员更为直接、方便的接口,习惯使用 JAVA 做编码的程序员,在使用 C/C++ 进行文本编码相关的操作时,常会感到困惑。本文的目的在于以常用的 Unicode(UCS-2)、GB2312、UTF8 三种编码为例,分析不同编码在实用中的关系,特别是 C/C++ 中,怎样处理各种编码的问题。

编码处理常见的问题

  • 1. 将内存中编码 A 的字符串以编码 B 格式处理成字节流写入文件
  • 2. 将原本以 A 编码组成的文件以字节流形式读入内存、并以编码 B 解析为字符串。

第一种情况,可能造成数据的变化、失真。
如果使用 JAVA 语言,发生这种错误的情况稍少一些,因为在 JAVA 中没有 wstring 这种概念,在内存中的 String,使用的编码都是 Unicode,其中的转换对于程序员来讲是透明的。只要使用输入 / 输出方法时注意字节流的字符集选择即可。
例如,编码为中文 GB2312 的“标准”字符串被读入内存后转存为 UTF8 的过程:

图 1. 文件转换编码的 JAVA 处理方式

文件转换编码的 JAVA 处理方式

但 C/C++ 编程,由于通常使用 char、string 类型的时候比较多,特别是进行文件读写,基本都是操作 char* 类型的数据。并且也没有像 JAVA 中 getByte(String charsetname) 这种函数,不能直接根据字符集重新编码得到字符串的 byte 数组。这时候,我们使用的 string 其实就一般不是 Unicode,而是符合某种编码表的。这使得我们往往困惑于 string 的编码问题。假设有 utf8 的字符串“一”(E4 B8 80),而我们错误的认为它是符合 gb2312(编码 A)的,并将其转换为 utf8(编码 B),这种转换结果是破坏性的,错误的输出将永远无法正确识别。
依然以“标准”为例,这是一个正确的转换:

图 2. 文件转换编码的 C/C++ 处理方式

文件转换编码的 C/C++ 处理方式


第二种情况,则是更常见到的。例如:浏览器浏览网页时的发生的乱码问题;在写 XML 文件时,指定了 < ?xml version="1.0" encoding="utf-8" ?> 然而文件中却包含 GB2312 的字符串——这样经常会导致 XML 文件 bad formatted,而使得解析器出错。
这种情况下,其实数据都是正确的,只要浏览器选择正确的编码,将 XML 文件中的 GB2312 转换为 UTF8 或者修改 encoding,就可以解决问题。
需要注意的是,ASCII 码的字符,即单字节字符,一般不受编码变动影响,在所有编码表中的值是一样的;需要小心处理的是多字节字符,例如中文语言。

 

编码转换方法

一般的编码转换,直接做映射的不太可能,需要比较多的工作量,大多情况下还是选择 Unicode 作为转换的中介。

使用库函数

如前文所说,JAVA 的 String 对象是以 Unicode 编码存在的,所以 JAVA 程序员主要关心的是读入时判断字节流的编码,从而确保可以正确的转化为 Unicode 编码;相比之下,C/C++ 将外部文件读出的数据存为字符数组、或者是 string 类型;而 wstring 才是符合 Unicode 编码的双字节数组。一般常用的方法是 C 标准库的 wcstombs、mbstowcs 函数,和 windows API 的 MultiByteToWideChar 与 WideCharToMultiByte 函数来完成向 Unicode 的转入和转出。

这里以 MBs2WCs 函数的实现说明 GB2312 向 Unicode 的转换的主要过程:

清单 1. 多字节字符串向宽字节字符串转换
wchar_t * MBs2WCs(const char* pszSrc){ 
    wchar_t* pwcs = NULL; 
    intsize = 0; 
    #ifdefined(_linux_) 
        setlocale(LC_ALL, "zh_CN.GB2312"); 
        size = mbstowcs(NULL,pszSrc,0); 
        pwcs = new wchar_t[size+1]; 
        size = mbstowcs(pwcs, pszSrc, size+1); 
        pwcs[size] = 0; 
    #else
        size = MultiByteToWideChar(20936, 0, pszSrc, -1, 0, 0); 
        if(size <= 0) 
            returnNULL; 
        pwcs = new wchar_t[size]; 
        MultiByteToWideChar(20936, 0, pszSrc, -1, pwcs, size); 
    #endif 
    returnpwcs; 
 }

相应的,WCs2MBs 可以将宽字符串转化为字节流。

清单 2. 宽字节字符串向多字节字符串转换
char* WCs2MBs(const wchar_t * wcharStr){ 
    char* str = NULL; 
    intsize = 0; 
    #ifdefined(_linux_) 
        setlocale(LC_ALL, "zh_CN.UTF8"); 
        size = wcstombs( NULL, wcharStr, 0); 
        str = new char[size + 1]; 
        wcstombs( str, wcharStr, size); 
        str[size] = '\0'; 
    #else
        size = WideCharToMultiByte( CP_UTF8, 0, wcharStr, -1, NULL, NULL, NULL, NULL ); 
        str = new char[size]; 
        WideCharToMultiByte( CP_UTF8, 0, wcharStr, -1, str, size, NULL, NULL ); 
    #endif 
    returnstr; 
 }

Linux 的 setlocale 的具体使用可以参阅有 C/C++ 文档,它关系到文字、货币单位、时间等很多格式问题。Windows 相关的代码中 20936 和宏定义 CP_UTF8 是 GB2312 编码对应的的 Code Page[ 类似的 Code Page 参数可以从 <

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值