Qt备忘录之一:中文字符串处理

由于工作上的需要,近期开始学习Qt。学习的心得将陆续、不定期地进行更新。也欢迎各位朋友前来指正。

目前顾毅用的是VS+QtPlugIn,Qt版本为4.8.6。

在Qt中新建一个工程,在main.cpp中写入以下代码:

[code lang="cpp" collapse="false"]
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel *label = new QLabel("中文");
label->show();
return a.exec();
}

[/code]

直接编译出来的结果如下所示:

显见是编码不正确,这个问题在刚接触VC++的时候也头疼了挺久。在网上查了一下资料,无非是使用setCodecForXXX()和tr()这两种方法。

setCodecForXXX()解析:

这一系列的函数有三个,分别是:

[code lang="cpp" collapse="false"]
void QTextCodec::setCodecForCStrings(QTextCodec *<i> codec</i>)
void QTextCodec::setCodecForTr(QTextCodec *<i> codec</i>)
void QTextCodec::setCodecForLocale(QTextCodec *<i> codec</i>)
[/code]

这三个函数分别用于设置QString、tr和本地语言环境的编码格式。对应的,以下三个则是获取当前使用中的编码格式:

[code lang="cpp" collapse="false"]
QTextCodec* QTextCodec::codecForCStrings()
QTextCodec* QTextCodec::codecForTr()
QTextCodec* QTextCodec::codecForLocale()
[/code]

使用以上的三对方法,可以实现对字符串编码的指定和获取。Qt支持的文字编码大约有50种,详情可参考官网上的说明(http://qt-project.org/doc/qt-4.8/QTextCodec.html)。其中,简体中文可以使用名称“GBK”或者“GB18030”或者“GB2312”作为编码名称来指定。在Qt平台中,这三种编码将不作区分。指定编码格式的示例如下:

[code lang="cpp" collapse="false"]
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB18030"));
[/code]

如果不清楚本地系统采用什么编码,也可以使用如下的语句以保证编码与本地系统相匹配:

[code lang="cpp" collapse="false"]
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
[/code]

或者

[code lang="cpp" collapse="false"]
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("SYSTEM"));
[/code]

通过强制指定编码格式,可以实现中文字符串的本地正确显示,却不能保证编译出来的程序在其他电脑上也能正确展现。因此使用setCodecForXXX()并不是合适的解决方案。

tr()是什么?

根据Qt的官方文档(http://doc.qt.io/qt-4.8/qobject.html#tr),tr()的原型是:

[code lang="cpp" collapse="false"]
QString QObject::tr char * sourceText, const char * disambiguation = 0, int n = -1)
[/code]

官方的说明如下:

Returns a translated version of sourceText, optionally based on a disambiguation string and value of n for strings containing plurals; otherwise returns sourceText itself if no appropriate translated string is available.

也就是说,tr()的作用是把sourceText的“翻译版本”返回,这个翻译结果是根据“消歧义字串”disambiguation和“复数”n得出,如果没有找到对应的翻译结果,将原值返回。

csdn的dbzhang800之前写过文章,详细的解析了tr()的调用过程,顾毅不再赘述,请点击原文(Qt中translate、tr关系 与中文问题)查阅。根据dbzhang800的分析,我们可以知道,最终执行的函数实际是:

[code lang="cpp" collapse="false"]
QString QCoreApplication::translate(const char * context, const char * sourceText, const char * disambiguation = 0, Encoding encoding = CodecForTr)
[/code]

因此,tr()实际上也是需要指定一个编码规则的(通过void QTextCodec::setCodecForTr(QTextCodec * codec)进行设定;如未设定,将默认使用ASCII)。所以,QString str = tr("中文");这种使用方法,也可能产生问题。

tr()推荐的用法是“翻译”,因此可以考虑将程序中的字串用英文表示,再在翻译文档中转换为中文。这样可以从根本上解决中文字符串在程序中的显示问题。

二零一五年二月廿五日

顾毅写于厦门