先给出乱码的解决方案:
若是Qt5,则在pro文件中加入下面这段代码:
greaterThan(QT_MAJOR_VERSION, 4): {
QMAKE_CXXFLAGS += -execution-charset:utf-8
}
若是Qt4,则在main.cpp中加入下面这段代码:
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#ifdef Q_OS_LINUX
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#elif defined (Q_OS_WIN)
QTextCodec *codec = QTextCodec::codecForName("GB2312");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#endif
关于Qt的乱码问题,以下是个人见解,可能有错误之处,欢迎指出。
要弄清楚Qt中的乱码问题,首先需要清除2个概念:
- 源码字符集(the source character set):源码文件是使用何种编码保存的
- 执行字符集(the execution character set):可执行程序内保存的是何种编码(程序执行时内存中字符串编码)
Qt为了保证跨平台,源码字符集统一采用的是带 BOM 的 utf-8格式,而在不同的系统上执行字符集的是不同的,Windows 一般用的GBK(GB2312),linux一般用的是不带BOM的UTF-8。
所以在windows系统下Qt5环境中,解决乱码的办法有pro文件中加
QMAKE_CXXFLAGS += -execution-charset:utf-8
或者在每个源文件的最上方加:
#pragma execution_character_set("utf-8")
这两者的原理都是将windows下的执行编码变成带BOM的utf-8格式,这样就和源码字符集一致,解决了乱码问题,这个方法在linux系统下也可以解决乱码问题,原理也是一致的。
但是在Qt4的环境下,上面2中方案的代码都是不识别的,所以在Qt4的环境下需要按以下方式解决乱码问题:
若是在windows系统下:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));
原理是将windows系统下QString中的中文字符用GB2312的编码存储,即将源码字符集变成GB2312的格式,这样源码字符集也和执行字符集一致了,都变成了GB2312。
若在linux系统下:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
Linux下产生乱码的原因是源码字符集是带BOM的utf-8格式,而执行字符集是不带BOM的uft-8格式,这2种格式也是有区别的,同样会导致乱码。所以上面这句的原理是将QString存储的中文字符的源码字符集变成不带BOM的uft-8格式,这样源码字符集也和执行字符集一致了,都变成了不带BOM的uft-8格式。注意与上面的#pragma execution_character_set("utf-8")进行区别。
有一种万能的解决乱码的方式,那就是用QString::fromLocal8Bit函数,原理是QString全部以QTextCodec::setCodecForLocale函数指定的编码将字符串转成Unicode,在运行时再转成对应的执行编码,自然可以保持两者一致,解决乱码问题。若没有显示指定QTextCodec::setCodecForLocale,则windows下是GB2312,linux下是UTF-8。但是若主函数中用QTextCodec::setCodecForLocale(codec)指定的编码不对,在读取第三方输入的时候(如QProcess读取控制台消息),QString::fromLocal8Bit一样会导致乱码,例如:
在windows系统下,首先指定QTextCodec::setCodecForLocale("UTF-8"),
之后用QProcess读取控制台消息:
QString outputStr = QString::fromLocal8Bit(process.readAllStandardOutput());
由于windows上控制台的编码是GB2312,而这个时候Qt认为是UTF-8,自然导致了乱码,这个时候可以用如下方式解决:
QString outputStr = QTextCodec::codecForName("GB2312")->toUnicode(
process.readAllStandardOutput());
即直接说明当前的字段是GB2312编码即可。