中文编码一直是个恼人的问题,目前还没有想到一个比较完美的解决方案。姑且先列下出现问题的时机,以及涉及到的问题及症状表述如下。
注:当前的本地化设置都是
setlocale(LC_CTYPE, "zh_CN.GB2312");
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
1.使用的qt的webview在我的机子上显示网页是乱码,经查证发现使用的是西欧的编码对gb2312进行解码,而在zz那边是对的,估计跟我的系统的默认编码有关。
web->setHtml(tr(result.c_str()), url);,实际上tr可以去掉,经测试去掉也可以,因为html里面的开头本身已经还有gb2312,按常理来说,应该可以识别出来。实际上应该做的是要转换成unicode的QString,修改如下:
web->setHtml(QString::fromLocal8Bit(result.c_str()), url);
奇怪,我发现如果把原来的默认主页由baidu(gb2312),改成google(utf-8),发现页面显示正常,再之后搜索结果的显示也正常了。然后再改成baidu,发现baidu依然是乱码,但是搜索后的页面是正常的。或许是我的这两处修改起了作用。
或者本身它不像普通的浏览器可以直接从html里分析出来,而是使用unicode编码,所以上面我用QString::fromLocal8Bit(result.c_str())做了正确的转换。
2.用qt的xml部件读取我的含中文的xml文件时,中文显示为乱码。经查证我的xml文件的编码方式为ANSI
解决方法:将文件保存为utf-8格式就可以了,这说明qt xml组件读文件默认使用的是utf-8.
3.界面文字中文显示
所有用户可见文字,均应使用tr包装。
4.http请求中的url编码:在我这边,在窗口中输入,中国,qt利用string str_item=(item->text(0)).toAscii().data();再显示得到的是乱码。
注意toAscii()函数,当没有设置时,它会转成latin1编码。估计就是转成了latin1.或者把超出范围00-的字符屏蔽直接变成了?.
QByteArray QString::toAscii () const
Returns an 8-bit ASCII representation of the string as a QByteArray.
If a codec has been set using QTextCodec::setCodecForCStrings(), it is used to convert Unicode to 8-bit char; otherwise this function does the same as toLatin1().
QByteArray QString::toLocal8Bit () const
Returns the local 8-bit representation of the string as a QByteArray. The returned byte array is undefined if the string contains characters not supported by the local 8-bit encoding.
QTextCodec::codecForLocale() is used to perform the conversion from Unicode.
实际上当我把toAscii().换成toLocal8Bit () ,这部分乱码就消失了。但在QWebView里的显示仍然错误。
再看一下
void QTextCodec::setCodecForCStrings ( QTextCodec * codec ) [static]
Sets the codec used by QString to convert to and from const char * and QByteArrays. If the codec is 0 (the default), QString assumes Latin-1.
Warning: Some codecs do not preserve the characters in the ASCII range (0x00 to 0x7F). For example, the Japanese Shift-JIS encoding maps the backslash character (0x5A) to the Yen character. To avoid undesirable side-effects, we recommend avoiding such codecs with setCodecsForCString().
Warning: This function is not reentrant.
See also codecForCStrings() and setCodecForTr().
以及
The QTextCodec class provides conversions between text encodings.
Qt uses Unicode to store, draw and manipulate strings. In many situations you may wish to deal with data that uses a different encoding. For example, most Japanese documents are still stored in Shift-JIS or ISO 2022-JP, while Russian users often have their documents in KOI8-R or Windows-1251.
Qt provides a set of QTextCodec classes to help with converting non-Unicode formats to and from Unicode. You can also create your own codec classes.
QTextCodecs can be used as follows to convert some locally encoded string to Unicode. Suppose you have some string encoded in Russian KOI8-R encoding, and want to convert it to Unicode. The simple way to do it is like this:
QByteArray encodedString = "…";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QString string = codec->toUnicode(encodedString);
After this, string holds the text converted to Unicode. Converting a string from Unicode to the local encoding is just as easy:
QString string = "…";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QByteArray encodedString = codec->fromUnicode(string);
综上可以看成,即使设置
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
qt本身使用的编码还是unicode,设置的只是编码器,在调用to***或者from***等函数时会使用它进行与unicode编码之间的转换。
5.下载的网页的google采用的utf-8编码无法正常显示
观察在开始的main里有如下设置:
setlocale(LC_CTYPE, "zh_CN.GB2312");
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
而显示的时候是这样的:
string result=display.show();
QWebView *web = web_view_list.at(index-1);
web->setHtml(tr(result.c_str()), url);
由上可见上述的编码设置都是gbk,本地设置也是gbk,但我们从google下载的是utf-8编码的。result是本应该是gb2312编码,但是由于其直接接受的是google的页面结果,所以实际上内部是utf-8编码。由于setCodecForTr已经设置编码器是gbk,这样会直接把本来是utf-8的编码当成gbk进行解码。
所以显示的时候我们需要对其编码转换,将utf-8转换为gbk。具体方式如下,
QString to_utf = QString::fromUtf8(s.c_str());
return string(to_utf.toLocal8Bit().data());
由于QString使用的是gbk编码,所以我们把utf-8转换为他的形式,然后在得到本地化的表示。这样就可以处理utf-8的网页了。
6.最后输出到浏览器显示的时候
如何处理本地化以及国际化支持的问题。
目前编码处理方式:
由于一开始缺少国际化的设计,因此目前在内部处理采用的是本地化的sting,而按照国际化的要求,实际上内部数据处理,应该使用wstring。但是因为我们目前的处理仅是进行了正则表达式的匹配,所以内部编码是何种形式基本不受影响。但是因为需求往往是变化的,因此这样的内部采用string表示的方法是不行的。
比如如果进行要进行字符串的排序,交换两个字符,得到字符的数目,对于汉字这样的类型用sting就无法处理了。string只是把它们的编码当成了独立的char处理,根本不知道字符信息。这点虽然适用于正则式,但是其他的情况就不行了,因此涉及国际化,内部应当采用wstring保存数据,进行各种计算。
另外,qt支持国际化的编程。这点也没有利用,比如很多字符串全部硬编码到了程序中,实际应该使用qt提供的tr工具。
由于目前我们假设运行在中文环境下,即使如此也是要进行一些编码转换及维护工作。我们假设在内部默认采用gb2312编码。即我们假设查询输入的编码是以gb2312的形式保存的,如果网站的ie是其他形式,则就要从gb2312转换。同时我们假设下载来的页面都是gb2312类型,如果不是也要转换为gb2312,因此我们以gb2312为标准编码。因为我们要在同一个上下文中处理,所以必须保证这样的被处理的文本具有相同的编码,因为它们最后将被同样对待的方式进行显示。而gb2312只是为了统一而设定的标准。
真正的国际化应该是这样的:
对源程序中的所有文本用英文书写,并用tr包裹。将这些文字做成资源文件。
设置本地化。
程序内部采用wstring进行计算,当用户从界面输入时,要将这个输入,转换为wstring类型保存。注意所有的从文件读入也要转换为wsting类型的。从网络上的也是,同时统一编码。
后面输出的时候,在完成响应的本地化转换。