Qt5中的字符串乱码问题
来源:互联网 发布:matlab 矩阵相似程度 编辑:程序博客网 时间:2024/05/23 01:57
先例举几种Qt5中QString使用汉字的可能方法与结果:
(以下结果适用用MSVC编译,工程使用Unicode字符集或多字节字符集的情况) //可以看出,与工程使用何种字符集无关
测试代码源文件ASCII编码保存
源文件UTF-8无BOM保存源文件UTF-8且有BOM保存
(需要使用VS2010SP1且加入
#pragram execution_character_set("utf-8"))
QString test = "测试字符串"; 结果为乱码;出现编译错误结果正确显示字符串“测试字符串”QString test =QString::fromLatin1("测试字符串"); 结果为乱码,与1不同;出现编译错误结果为乱码
QString test =
QString::fromUtf8("测试字符串"); 结果为乱码,且与1相同;出现编译错误结果正确显示字符串“测试字符串”QString test =
QString::fromUtf16("测试字符串"); 结果不能通过编译; 出现编译错误出现编译错误QString test =
QString::fromWCharArray("测试字符串"); 结果不能通过编译;出现编译错误出现编译错误
可以看到使用第三种方法解决了中文乱码问题,这里要注意在每一个被保存为带BOM的Utf-8编码的.cpp文件中需要加上如下预编译语句:
#if defined(_MSC_VER) && (_MSC_VER >= 1600) //_MSC_VER是微软C/C++编译器——cl.exe编译代码时预定义的一个宏。
//需要针对cl编写代码时, 可以使用该宏进行条件编译。
# pragma execution_character_set("utf-8")
#endif
分析:
(1)保存源文件为Utf-8带Bom编码格式是为了在VS2010与QtCreator中都可以使用同一编码规则打开与修改,如果两方同时使用gb2312编码打开与修改源代码也是可以的,源码中的中文不会出错。
(2)# pragma execution_character_set("utf-8") 预编译命令是告诉编译器在使用字符串时使用utf-8的编码格式,与源文件的编码格式可以说是没有关系的,源文件保存为gb2312编码时仍然可以使用该预编译命令。
(3)由于# pragma execution_character_set("utf-8") 预编译命令在VS2013中已经不再支持.
对于中文乱码问题最根本的解决方案其实是:
(1)在源文件中代码字符串只使用英文,在翻译文件中翻译为中文。
(2)在确实需要将C语言char*类型中文字符串转换为QString类型中文字符串时使用如下方法:
QTextCodec* codec=QTextCodec::codecForName("gb2312");
m_nodeValue = codec->toUnicode(m_clientNode.itemValue);
VS因为为了Windows经常要和ANSI编码(可能是ASCII,也可能混合GBK等多字节编码)区分,所以要求UTF-8之前必须有BOM。Linux因为全盘UTF-8化,UTF-8又和ASCII兼容,而GCC设计者多数也只用英文在程序里,结果好几年Linux只用没有BOM的UTF-8。起始这里处处体现着Linux开发缺乏统一长远计划。Windows因为较早接触国际市场,很早就遇到各种本地编码的问题,所以这方面比较明智(要求UTF-8加BOM)。Linux则对付本地编码的情况不多,所以会有兼容性问题。
1。即使把vs设置为识别 NO BOM,文本显示没有问题,但编译还是有问题。通过预编译可以看到。
问题在于有时候,比如:
class A
{
int a; //测试(utf-8编码会显示乱码,如果解释不好的情况会把下一行作为注释处理)
int b; (这一行可能会被解释为注释)
}
那么,预编译出来的效果是:
class A
{
int a;
}
2.解决办法:注释都这样写 /*(空格) 测试(空格)*/
这样,虽然显示是中文乱码,但不会出现上述编译问题。
要搞清楚这个问题,先要弄明白编码。但是编码问题实在太复杂,这里肯定讲不开。
我先找一个例子,比如:“中文” 的 Unicode 码点/UTF8编码/GBK 分别是多少。
先去这个网站,输入 “中文” 查询对应的 Unicode 码点/UTF8编码:
http://www.mytju.com/classcode/tools/encode_utf8.asp
Unicode的码点分别是(十进制):中(20013),文(25991)。
对应的UTF8编码分别(16进制): 中(E4B8AD),文(E69687)。
然后再去下面这个网站,输入 “中文” 查询对应的 GBK 编码:
http://www.mytju.com/classcode/tools/encode_gb2312.asp
GBK编码16进制(GBK内码)分别是:中(D6D0),文(CEC4)。
现在已经知道了"中文"的UTF8和GBK编码的具体值。
我们再看看VC2010是怎么处理的。
1. 先看 无 BOM 的 UTF8 编码的代码 (utf8_no_bom.cpp)
01
// utf8 no bom
02
// 文件中包含不能在当前代码页(936)中表示的字符
03
#include <stdio.h>
04
05
int
main() {
06
const
char
* str =
"中文"
;
07
for
(
int
i =
0
; i < sizeof(str); ++i) {
08
printf(
"0x%x "
, str[i]&
0xFF
);
09
}
10
return
0
;
11
// Output:
12
// 0xe4 0xb8 0xad 0xe6
13
}
输出是:0xe4 0xb8 0xad 0xe6。
感觉好像是对的。
但是,先别急:VC编译时输出了一条警告信息:
utf8_no_bom.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。
请将该文件保存为 Unicode 格式以防止数据丢失。
潜台词就是,你这个代码有GBK不能表示的字符,请用Unicode方式保存。
VC根本就没把 代码(utf8_no_bom.cpp) 当作UTF8,VC只是把它作为GBK处理罢了。
那为什么又输出了正确的结果呢?
因为 VC 把 (utf8_no_bom.cpp) 当作 GBK,而编译时也要转换为本地编码(也是GBK)。
因此,UTF8编码的 “中文”,被VC当作编码为 “0xe4 0xb8 0xad 0xe6” 的其他中文处理了。
VC已经不知道 “0xe4 0xb8 0xad 0xe6” 是对应 “中文” 字面值了。
但是在GBK(实际是无BOM的UTF8)转GBK的过程中,发现了一些UTF8编码的字符并不是
GBK能表达的合理方式,因此就出现了那个C4819编译警告。
2. 再看带BOM的UTF8是怎么处理的 (utf8_with_bom.cpp)
01
// utf8 with bom
02
#include <stdio.h>
03
04
int
main() {
05
const
char
* str =
"中文"
;
06
for
(
int
i =
0
; i < sizeof(str); ++i) {
07
printf(
"0x%x "
, str[i]&
0xFF
);
08
}
09
return
0
;
10
// Output:
11
// 0xd6 0xd0 0xce 0xc4
12
}
编译没有警告,但是输出有问题:0xd6 0xd0 0xce 0xc4。
源文件明明是 UTF8 编码的格式"0xe4 0xb8 0xad 0xe6”,
怎么变成了 “0xd6 0xd0 0xce 0xc4” (这个是GBK编码)?
这就是VC私下干的好事:它自作聪明的将UTF8源代码转换为GBK处理了!
VC为何要做这样蠢事?
原因是为了兼容老的VC版本。
因为以前的VC不能处理UTF8,都是用本地编码处理的。
3. 在看看真的GBK是怎么处理的 (gbk.cpp)
01
// gbk
02
#include <stdio.h>
03
04
int
main() {
05
const
char
* str =
"中文"
;
06
for
(
int
i =
0
; i < sizeof(str); ++i) {
07
printf(
"0x%x "
, str[i]&
0xFF
);
08
}
09
return
0
;
10
// Output:
11
// 0xd6 0xd0 0xce 0xc4
12
}
没有编译错误,输出也和源代码一致:“0xd6 0xd0 0xce 0xc4”。
因为源文件就是GBK,cl在编译时GBK转化为GBK,没有改变字符串。
只是,现在很多人不想用GBK了(因为只能在中国地区用,不能表示全球字符)。
到这里,可以初步小结一下:
- VC编辑器和VC编译器是2个概念,VC编辑器支持UTF8并不能表示VC编译器也支持UTF8
- VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏,因为会本地编码冲突)
- VC编译器从2010开始重要可以支持UTF8了(虽然支持方式很不优雅)
4. 看看VC2010是怎么处理带BOM的UTF8的 (utf8_with_bom_2010.cpp)
VC2010重要增加了UTF8的编译支持(#pragma execution_character_set("utf-8")
),
具体查看:
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec
01
// utf8 with bom (VC2010), 这句是重点!
02
#pragma execution_character_set(
"utf-8"
)
03
04
#include <stdio.h>
05
06
int
main() {
07
const
char
* str =
"中文"
;
08
for
(
int
i =
0
; i < sizeof(str); ++i) {
09
printf(
"0x%x "
, str[i]&
0xFF
);
10
}
11
return
0
;
12
// Output:
13
// 0xe4 0xb8 0xad 0xe6
14
}
没有编译错误,输出也和源代码一致:“0xe4 0xb8 0xad 0xe6”。
UTF8编码,UTF8输出。完美!
回到 Qt5 的中文输出问题。
Qt默认支持 VS2010/MinGW/Gcc 等编译器,而它们现在都已经真正支持UTF8了。
当然,VS2010 对UTF8的支持会入侵代码(#pragma execution_character_set("utf-8")
)。
看看Qt官方论坛别人是怎么说的:
http://qt-project.org/forums/viewthread/17617
Nothing special need to do, it will works by default.
If the exec-charset of your your compiler is UTF-8.
简单的说,从Qt5开始,源代码就是默认UTF8编码的。
当然,VC2010编辑器对带BOM的UTF8也是认识,只可惜VC2010编译器根本承认它是UTF8!
在继续看官方论坛的回复:
You can write a simple example like this
01
#include <QApplication>
02
#include <QLabel>
03
04
#
if
_MSC_VER >=
1600
05
#pragma execution_character_set(
"utf-8"
)
06
#endif
07
08
int
main(
int
argc,
char
*argv[])
09
{
10
QApplication a(argc, argv);
11
QLabel label(
"ąśćółęńżź"
);
12
label.show();
13
14
return
a.exec();
15
}
If other people can reproduce your problem, you can file a bug.
教完整的解决方案(增加了Qt4/Qt5和非VC环境的判断):
01
// Coding: UTF-8(BOM)
02
#
if
defined(_MSC_VER) && (_MSC_VER >=
1600
)
03
# pragma execution_character_set(
"utf-8"
)
04
#endif
05
06
#include <QApplication>
07
#include <QTextCodec>
08
#include <QLabel>
09
10
int
main(
int
argc,
char
* argv[])
11
{
12
QApplication app(argc, argv);
13
14
#
if
QT_VERSION < QT_VERSION_CHECK(
5
,
0
,
0
)
15
#
if
defined(_MSC_VER) && (_MSC_VER <
1600
)
16
QTextCodec::setCodecForTr(QTextCodec::codecForName(
"GB18030-0"
));
17
#
else
18
QTextCodec::setCodecForTr(QTextCodec::codecForName(
"UTF-8"
));
19
#endif
20
#endif
21
22
QLabel *label =
new
QLabel(QObject::tr(
"你好!"
));
23
label->show();
24
25
return
app.exec();
26
}
有以下几种类型(源代码必须是带BOM的UTF8):
- Qt5+/VC2010+: 包含了
# pragma execution_character_set("utf-8")
已经支持中文 - Qt5/VC2008-: 这个暂时误解(我还没找到方法)
- Qt4+/VC2008-: 采用以前老的方式, 指定代码为 “GB18030-0” 编码
- Qt4/Qt5/Linux: 只要是默认的UTF8环境, 应该都没问题
其实这个问题不是Qt特有的, 追根溯源还是C/C++和编译器的问题.
即使是支持UTF16的Java也同样难逃此问题.
- Qt5中的字符串乱码问题
- QT5 中的乱码问题
- qt5.0在vs中的乱码问题。
- Qt5中文乱码问题
- QT5 乱码问题
- QT5 乱码问题 II
- QT5 中乱码问题
- Qt5中文乱码问题
- Qt5乱码问题
- Qt5中文乱码问题
- Qt5之中文乱码问题
- QT5.2.1 中文乱码问题
- QT5出现中文乱码问题
- Qt5中文显示乱码问题
- QT5读取中文乱码问题
- QT5 解决中文乱码问题
- Qt5 中文乱码的问题
- QT5 解决中文乱码问题
- 進捗遅れをなくそう
- 理解Windows内核模式与用户模式
- ipad air的键盘推介(mark一下,备用,嘿嘿)
- [iOS]ARC下循环引用的问题
- ZK 7.0版本正式发布
- Qt5中的字符串乱码问题
- 帝国后台登陆超过5次解锁方式
- centos安装flash插件
- 多线程应用调试
- JAVA内存管理【1.1 java是如何管理内存的】
- ant脚本实现自动编译
- 理解MySQL——索引与优化
- jquery 改变下拉列表选项
- 两种分页排序比较