1-Qt-中文乱码
问题的本质
Qt是一个跨平台的库,因此常被用在各种常见的操作系统上进行软件开发;比如linux 或者 windows;
而在软件开发过程中,经常会遇到中文乱码的情况;很多情况下在网上搜索一个解决方案发现也好使,也就不去细究了;但是这个方案在其它情况下又不好用;
其本质原因是没有搞清楚当前开发环境不同模块之间的编码转换问题;
解决方案
在Qt5.0以后,推荐使用的解决方案一般是采用QString::toLocal8Bit(...)
和 QString:: fromLocal8Bit(const char *str, int size = -1)
但是这个方案的使用还得注意前面所说的 开发环境不同模块间的编码问题;
一般影响编码的模块包括: 操作系统, 编译器, 文本的格式;
所以在开发过程中,上述三个模块支持的编码格式心里一定要有数。否则发生乱码是在所难免的;
编码概述
编码是一门大学问,这里不可能讲清楚,但是了解是很有必要的;这里只讲对我们解决乱码有用的地方;
-
Unicode是一种字符编码,目前是国际通用编码;也就是大家约定的一种为字符编码的规则;否则大家各自订一套,那么在这个互联网联通万物的世界,语言不通;它是让每个字符和一个数字对应起来,仅此而已;
-
utf8 utf16 utf32:上面Unicode只是定义了规则,至于如何将规则存储,就有了这三种存储方式;
-
目前互联网,或者说使用最广泛的编码存储规则,就是utf8;
-
BOM(byte order mark): 为了区分Unicode是采用 哪一种存储格式,有分为是否带BOM; 可是这个BOM并不是以明文的方式呈现在文本中,所以并没没有被广泛使用; 原因很多,,这里不拓展开来;
既然不使用BOM,各种语言也有他们区分Unicode存储方案的解决方法:Python的 # -- coding: utf-8 --,Perl的use utf8 等等; -
使用带BOM的UTF-8: 只有微软使用了BOM来区分:将UTF-8 和 ASCII 等编码明确区分开;「UTF-8」和「带 BOM 的 UTF-8」的区别就是有没有 BOM。即文件开头有没有 U+FEFF。而且开头并不是可见的明文;
小结:讲到这里,可以知道的一点是,Unicode字符编码是有国际使用最广泛的;开发的时候也一般采用的都是 Unicode的编码规则;
当然也有其它编码规则: 比如ASCII, GB2312, GBK等等;
其中linux 常用 utf-8, 而windows在国产机(中国)使用GBK
因此,为了编码间能正常识别转换,一般先将编码转换为 Unicode编码规则,在转成本地编码规则
如: GB2312
⇒
\Rightarrow
⇒ Unicode
⇒
\Rightarrow
⇒ GB2312
实战
了解了上述的原理后,我们选用了最常见发生乱码的一个案例来进行实战;
环境准备
- Qt 版本5.9
- windows10操作系统
在Windows平台下,进入DOS窗口,输入:chcp
可以得到操作系统的代码页信息,你可以从控制面板的语言选项中查看代码页对应的详细的字符集信息。
例如:
我的活动代码页为:936,它对于的编码格式为GBK。 - MSVC编译器(具体MSVC2015 64位), 这里配置成支持utf-8编码格式
MSVC默认对中文编码: 采用GB2312或GBK编码,即使用两个字节表示汉字
当然可以设置成:支持utf-8
例如:在.pro文件中添加
msvc {
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
- 文本格式设置: 不带BOM的utf-8 和 带BOM的utf-8, 配置成不带BOM
在qt creator中可以直接设置;
效果
可以改变各种配置,去多体验和实践;下面给出一种方案;
ui->pushButton->setText("大梦无边");
//这是按照编译器的编码格式进行编码,这里我们设置MSVC为UTF-8
std::string dd = "丝路手动阀精神公路商店";
//这里是输出到磁盘的文件,由于是UTF-8的编码,而操作系统是GBK,所有显示出来是乱码
std::ofstream out;
out.open(dd);
out << dd <<std::endl;
out.close();
//将编码转成本地编码,也就是GBK, 输出的文件就不是乱码了
std::string covertToLoacal = QString::fromStdString(dd).toLocal8Bit().toStdString();
out.open( covertToLoacal);
out << dd <<std::endl;
out.close();
QString name = QString::fromStdString(dd);
this->setWindowTitle(name);
按照上面的设置出来的效果;