qt中文乱码原因分析及解决方案
首先说明几个基础概念
- UTF-8 BOM 和 UTF-8。BOM在文件头位置占三个字节,用来标识UTF-8编码,软件通过BOM来识别这个文件是否是UTF-8编码。
- 源码字符集。源码文件使用某种编码格式保存。
- 执行字符集。可执行程序内保存的编码(程序执行时内存中字符串编码)。
- QString中统一采用utf-16(Unicode)存储字符串。
- QString::fromxxx()函数。代表将字符串以对应格式去解析成Unicode,fromLocal8Bit()代表使用本地字符集(系统设置)转换成Unicode;fromUtf8代表从utf-8转换成Unicode。Qt程序运行的时候字符串编码在QString中实际都是以unicode编码存储的,通过使用QString::fromxxx()转换成转换成unicode存到QString中。
乱码产生的原因
中文处理的时候,编译器首先解析源码字符集,根据具体情况将源码字符集解析为执行字符集,再将执行字符集转换为QString的编码(unicode)。QString的编码是固定的,要想整个过程无乱码,那么源码字符集到执行字符集的转换必须确定。换句话说就是编译器必须明确文件的编码和执行字符集。这个不同的编译器的逻辑是不一样的。以MSVC和Mingw为例分析:
- MSVC
源码字符集:源文件有BOM的情况下按BOM解释,无则使用本地Locale字符集(随系统设置而变)。
执行字符集:使用本地Locale字符集(随系统设置而变)。
- Mingw
源码字符集和执行字符集默认都按utf-8解析。
因此乱码的原因有:
- 编译器解读源码字符集错误,比如utf-8的源码不带bom编译器会当成locale,执行字符集也是locale所以不需要转换,但是实际utf-8的编码到locale是需要转换的。
- 源码字符集到执行字符集的转换错误。比如需要解析执行字符集utf-8,需要使用fromUtf8。但是却使用了其它的转换方式fromXXX,这是使用了错误的转换算法。
- 字符解析错误。比如程序中的字符串二进制是utf-8的,设置执行字符集是loacle,那么解析就会出错。
解决方案
最好的解决方案是将源码保存成utf8 bom,执行字符集也选为utf8
对于MSVC,源码字符集之所以保存成 bom是因为只有bom 编译器才能识别出来源码字符集,执行字符集设置为utf8在C++98的MSVC上是没有什么好办法的,只能使用QString::fromUtf8设置转换算法。c++ 11比较方便,提供了设置执行字符集的方法 #pragma execution_character_set("utf-8")。
之所以说这是最好的解决方案,是因为这种设置在qt5以上的版本中具有良好的跨平台性,Mingw和GCC都支持这种方案。
采用这种方案无需再写QString::fromxxx()函数(此中情况下发现无论是在msvc还是mingw下,对于中文常量的处理加不加fromUtf8都能正常处理,分析了一部分源码和注释后猜测是因为从const char*到QString的隐式转换内部使用了QStringData保存字符串的空间,然后这个字符串 从 utf-8转码为unicode并拷贝到data)。
使用vs2010以上版本开发程序的时候,可以安装ForceUTF8(with BOM)插件,能够使新创建的工程文件都是BOM格式。
#pragma execution_character_set("utf-8")不需要硬编码到代码中,可以使用inc文件在pri文件中设置编译器和链接器flag参数即可
- 将#pragma execution_character_set("utf-8")保存在xxx.inc中
- 在pri中添加:
win32-msvc*:QMAKE_CXXFLAGS += -FI\"$$PWD/xxx.inc\"
win32-msvc*:QMAKE_CFLAGS += -FI\"$$PWD/xxx.inc\"
另外有一点需要注意,编译器根据ui文件生成的ui_xxx.h文件默认编码是utf-8(无BOM),里面涉及到的汉字都已经转换成了字符编码,所以ui文件生成的源码无需特殊处理。
应该避免的解决方案
- qt5之前有一种很不推荐的解决方案:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
Qt5版本取消了QTextCodec::setCodecForTr()和QTextCodec::setCodecForCStrings(方法,只剩下setCodecForLocale,这一个函数也只影响Qt对toLocal8Bit相关函数的编码方式。并且QObject::tr是用于程序国际化的,可以使界面文字翻译成不同的语言。如果使用QObject::tr,就应该全部用英文表示,然后借助Linguist翻译成中文,这样不会乱码了。
- 还有一种说法说用QStringLiteral也可以处理汉字乱码,其实它的功能是用来减少一次临时拷贝对象,用来提升性能的,有部分编码转换的功能,但是说它可以处理乱码,经过分析和实践发现毫无道理。
QStringLiteral是一个宏,在支持lambda表达式的c++11中,直接解析源码字符集到宽字节。不支持lambda的编译环境中等同于fromUtf8
只要保证源码字符集编译器识别正确就不会出现乱码,因为它是直接转换成了宽字符,和执行字符集没有关系(个人认为)
这种情况下,设置源码字符集为utf-8 bom,编译器因为bom的存在能够正确识别出源码字符集。但是执行字符集并没有设置,所以采用window系统默认的gbk作为执行字符集。因为QStringLiteral不经过执行字符集的转换,所以显示正常。
另外一种情况,源码字符集为utf-8,因为没有bom,msvc不知道这是什么编码,默认当成window系统默认的gbk作为源码字符集。但是真实编码应该是utf-8,源码字符集错了,转换成宽字节的时候也不正常了。
qt中文乱码原因分析及解决方案相关推荐
- Qt中文乱码原因及解决方案
本文主要分析了基于windows系统msvc2013编译器的Qt中文乱码. 概念 字库表:是一个系统支持的文字,符号,数字的集合. 编码字符集(字符集):我们平时所说的字符集就是这个,计算机以二进制的 ...
- 彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)
尊重作者,支持原创,如需转载,请附上原地址:https://blog.csdn.net/libaineu2004/article/details/19245205 一.Qt Creator环境设置 1 ...
- Qt中文乱码解决思路
最近项目中遇到不少的Qt中文乱码的问题,主要原因是客户的需求比较多,Qt版本有用4的版本的也有用5的版本,并且还有windows与linux跨平台的需求. 经常出现个问题是windows的解决了,源代 ...
- zhs16gbk对应mysql_NLS_LANG 数据库字符集中文乱码问题分析和解决
前言 已经有 3 年多没再关心或者遇到编码格式的问题了,一是离 Oracle 数据库操作远了,二是现在的 Terminal,IDE 和操作系统语言环境配置都很标准,比如清一色的 UTF-8 编码和 U ...
- php源码 乱码 通达oa_php中文乱码问题的终极解决方案汇总
前言 本文主要给大家介绍了关于php中文乱码问题的终极解决方案,分享出来供大家参考学习,在开始之前,我们先来谈谈为什么会出现中文乱码? 很多新手朋友学习PHP的时候,发现程序中的中文在输出的时候会出现 ...
- [转载]关于中文乱码问题的一些解决方案和经验
关于中文乱码问题的一些解决方案和经验 1.字节和unicode java内核是unicode的,就连class文件也是,但是很多媒体,包括文件/流的保存方式是使用字节流的.因此java要对这些字节流经 ...
- QT中文乱码解决思路和方法汇总
QT中文乱码解决思路和方法 中文编码一律使用QString::fromLocal8Bit()接口,原因是为了支持QT4版本.QStringLiteral()方法也可以使用,它是支持QT5版本的: CP ...
- QT中文乱码解决方法2
转载自:http://blog.163.com/seven_7_one/blog/static/162606412201032955449489/ QT中文乱码的解 2010-04-29 17:54: ...
- 万字长文总结JAVA几种常见的编码格式和乱码原因分析
你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 developer.ibm.com/zh/articles/j-lo-chine ...
最新文章
- ON、WHERE、HAVING的区别
- js实现图片轮播(终结版)
- QQ牧场在高速模式下的一些小bug
- C语言库函数的实战之一
- 常见设备分辨率大小,响应式必备啊
- 对C语言进行调试的最好方法是什么?
- html设置div页面最底,使用css让大图片不超过网页宽度
- Spring MVC 实践笔记
- 科兴生物董事长:两针建立免疫记忆 三针后抗体提升十倍
- curl php 禁用ip6,CentOS 6禁用IPv6解决curl Couldn’t resolve host或dns解析慢
- 记一次微信数据库解密过程
- Ubuntu——系统扩容(加硬盘)的学习笔记
- 新手如何使用Docker来搭建PHP开发环境?
- webpack.config.js====CSS相关:插件optimize-css-assets-webpack-plugin
- tp前后端不分离源码_Thinkphp5.0+Vue2.0前后台分离框架通使用后端源码
- 大白菜装机教程win10_大白菜U盘启动工具|大白菜超级U盘启动制作工具 V6.0_2009.25官方版下载...
- 美团网站底部超链接部分设计实现
- 安装java的心得体会_java实训心得体会范文
- Android 如何优雅的实现控件计时功能
- 我的世界JAVA挂机杀怪有经验_我的世界如何快速获得经验?