为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

从此乱码是路人

2014-03-31 37页 pdf 5MB 39阅读

用户头像

is_446021

暂无简介

举报
从此乱码是路人 相信大家在刚学 Qt的时候一定遇到过 #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QLabel lb; lb.setFont(QFont("Sans Serif", 24)); lb.setText(" 乱码其实是一件很容易的事情。 "); lb.show(); return a.exec(); } 学会了第一个 ...
从此乱码是路人
相信大家在刚学 Qt的时候一定遇到过 #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QLabel lb; lb.setFont(QFont("Sans Serif", 24)); lb.setText(" 乱码其实是一件很容易的事情。 "); lb.show(); return a.exec(); } 学会了第一个 Qt 例子, 很高兴, 于是想要做一点改变。 兴冲冲地输入一段比如 “XXX 是大神”的句子, 结果却发现, 显示的是乱码。 由于字符编码设置不当, 导致应用程序无法正常显 示文字,称之为乱码。 以之问老师,老师给你三行代码 QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); QTextCodec::setCodecForLocale(QTextCodec::codecForLocale()); QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale()); 当然,在此我也就不解释为什么中间那行 实际上是没有任何作用的了。不过你们真 的这么放心这三行代码嘛? 这三行代码,真的管用吗? 事实上,这三行代码, 是相当错误的打开方式! 让我们来看一个Windows7下的例子 这看上去很美好,不是么? 但是当我们使用非中文的Windows时 这究竟是为什么? ● 其实不仅仅是我们的程序,在其他很多地方都有乱码。 ● 打开一个网页,结果显示出来的是不知所云的外星文字。 ● 非英语国家的软件,曾经有过那么一段水火不容的历史。 ● 玩过日文游戏的人,可能都接触过 AppLocale这个神器。 ● 还有 9#论坛分为 GBK和 BIG5两种编码环境。 ● …… 这是一个很复杂的历史问题 首先,我们得承认有以下一些事实 ● 计算机只能存储二进制位。 8个二进制位是 1个字节。 1 个字节可以示 0~ 255之间的任何一个数字。 ● 文件,无论是「文本文件」还是「音乐文件」,或者是所 谓的「二进制文件」,本质上都只是一连串 0~ 255的数 字。这个序列被称为字节流。 ● 因此,我们眼中的「字符串」,在计算机看来,也不过是 一个字节流而已。 ● 表示「字符串」的过程,就是将字符映射为字节的过程。 美国人发明了 ASCII字符编码 英文字母很少,一 个字节就能全部囊 括,因此美国人只 发明了字节和英文 字符之间的一一映 射关系。 这就是 ASCII 。 然后人们发现一个字节不够用了 ● 欧盟 27个国家有大量拉丁语系的字符,远远超过了 256 所能容纳的数量。 ● 作为亚洲语言的代表,中日韩语言中所使用的汉字,仅仅 常用便已达到了数千。而截至清代,《康熙字典》已收录 汉字 47000有余。 ● 更不用提其他各种小语种的文字。 ● …… 既然一个不够,我们就来俩 ● 在美国人的 ASCII编码系统中, 128~ 255之间的数字几 乎没有使用。而凡是小于等于 127的数字,二进制表示中 首位都是 0;大于等于 128的数字,首位都是 1。 ● 这个特性很快被得到了运用。一般的想法是,在字节流 中,如果出现大于等于 0x80的字符,则被认为(可能) 是多字节编码的「前导字节」,需要同下一个字节一起构 成完整的「字符」。 ● 凭借这个,各个国家先后制定了自己的「多字节编码 规则」。比如简体中文第一个国家编码,就是 GB2312。 你埋怨我不懂你,你又何曾懂过我 ● 每个国家的文字编码「各自为政」,这导致不同国家 之间交换信息变得非常困难。传输文档之前要实现约 定双方使用的编码方式;当然这不是唯一的问题。 ● 更大的问题在于,你甚至不可能在一篇文档里,同 时插入德语字母和中文汉字!于是你在打印一篇语 言混用的文章的时候,很可能需要将文章分批打印, 然后把他们全部粘起来?! ● …… 我们还是坐下来好好研究一下吧 于是 Unicode诞生了 ● 20世纪 80年代末, Unicode统一码联盟成立。 ● 1991年十月发表第一个 Unicode,即 Unicode 1.0。 ● 2001年 3月, Unicode 3.1收录超过 65536个字符,正 式由双字节编码扩展为四字节编码。 ● 2005年 3月, Unicode 4.1收录了第十万个字符,其为马 来亚拉姆语的 Praslesham( പ്രേശല്ഷം )。 ● 2012年 1月 31日, Unicode 6.1发布。 UCS-2, UTF-8和 UTF-16 ● 事实上刚开始的时候, Unicode编码曾经只有 65536个字符空间。这个空间 被称为「基本多文种平面」。用恒定的两个字节表示所有字符,这种编码方 式被称为 UCS-2。 ● 当 Unicode字符超过 65536之后,参考「多字节编码」,通过双字节扩展四 字节的方式表示所有字符。这种编码方式被称为UTF-16。 ● 为了便于网络传输和数据处理,不至于因为遇到“ \0”而错误地以为文本结 束,以及兼容 ASCII码, UTF-8被定义。 UTF-8的每一个字符按规则编码 为 1~ 4任一字节组合。中文通常为 3字节长。 ● 当然,也有直接使用 4字节编码所有字符的编码方式,被称为 UTF-32或者 UCS-4。 用 GBK和 UTF-8编码的中文 Windows的历史遗留问题 ● 在 Unicode尚未成熟的年代,Windows是使用各个国家的多 字节编码,来支持每个国家的语言的。 ● 自 WinNT 发布之后, Windows 内核的 API 全部改成使用 UTF-16的编码方式,以更好地支持多语言。但是由于历史原 因, Windows仍然保留多字节编码的 API。 UTF-16的 API 以W结尾,而多字节编码以 A结尾。 ● 例如 CreateWindowA和 CreateWindowW。 ● 但是直到现在为止,很多Windows程序员仍然没有 Unicode 字符编码的相关知识,因此写出来的程序,就很容易乱码…… 说了这么多, 也该解决之前提到的问题了。 让我们先研究一下 C++的字符串常量 ● 编译器处理字符串常量,只是把引号里面的字节数组全部 复制,待程序运行的时候变成内存中的字节数组而已。 ● 因此以下几行等价(以 UTF-8编码保存 C++源文件): const char s1[] = " 最喜欢 C++ 了! "; const char s2[] = "\xe6\x9c\x80\xe5\x96\x9c\xe6\xac\xa2\x43\x2b" "\x2b\xe4\xba\x86\xef\xbc\x81"; const char s3[] = { 0xe6, 0x9c, 0x80, 0xe5, 0x96, 0x9c, 0xe6, 0xac, 0xa2, 0x43, 0x2b, 0x2b, 0xe4, 0xba, 0x86, 0xef, 0xbc, 0x81, 0x00 }; 然而 QString使用的是 UTF-16 ● std::string 本质上是字节数组,因此从 const char* 转换为 std::string不会有太大问题。以前大家写程序的时候不注意这方 面的东西,保存的文件自然也都是 GBK 的,在中文版 Windows下面也看不出什么问题。 ● 但是 Qt不同。 Qt从诞生开始就是国际化的项目,因此特别注 重这些东西。在兼顾了计算性能和存储性能之后, Qt小组决定 将 UTF-16作为 QString的编码格式。 ● 所以诸位源代码中出现的中文字符串常量,在被 Qt使用之前, 都经历了一次由「多字节编码」转换为 UTF-16的过程。 源文件中的「多字节编码」是什么? ● 如果不特别说明, Qt 4.x会认为源文件的编码是 Latin-1(西欧语言多 字节编码)。当然, Qt 5.x已经修正这个坏习惯,默认源文件是 UTF-8 来着。不过谁叫我们现在还在用 4.8呢? ● 就像 std::string做的一样, QString可以在必要的时候由 const char*隐 式 或 显 式 转 换 而 成 。 这 个 过 程 中 使 用 的 编 码 , 就 是 QTextCodec::codecForCStrings。 ● Qt有一个函数, QObject::tr,也可以将 const char* 转换为 QString。 这个过程中使用的编码方式由 QTextCodec::codecForTr指定。 ● 另外 QTextCodec::codecForLocale表明当前系统所用编码。一般中文 Windows应该是 GBK。中文 Linux则一般为 UTF-8。 但是 Qt Creator保存源文件的编码是 System!也就是 codecForLocale! GBK的源文件自然需要 GBK解码 碰 巧 中 文 Windows 的 codecForLocale 是 GBK ,因此在中文系统下面完全没有压力。 但是在非中文系统下就成了个悲剧 尝试用 US-ASCII解码 GBK字符串 尝试用 SHIFT-JIS解码 GBK字符串 这个时代用 GBK写程序就应该 让我告诉你们正确的打开方式 和我签订契约,使用 UTF-8吧! 然后改变那三行代码……不,两行代码 QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8")); 将 QObject::tr 和 const char* 的编码都改成 UTF-8 ,并 且使用 UTF-8 保存文件。这样就可以保证在任何语言的 操作系统上面都可以显示正确的中文。 但是要特别注意的是,修改 codecForLocale要慎重! 在 Qt 里面, codecForLocale 的作用主要有两个,一个 是与外部文件读写的时候使用的默认编码,一个是向命 令行输出信息( qDebug )使用的编码。 于是我们的程序终于不乱码了 Qt的整个框架都使用 UTF-16编码 ● 合理遵循 Qt的规则,基本不会出现字符乱码的问题。 ● 除了 const char*的隐式转换和 QObject::tr的转换之外, Qt事实上有更一般的字符编码转换方式。 // 我们的源文件是 UTF-8 格式的,因此建立一个 QString 。 QString s = QString::fromUtf8(" 这是 UTF-8 的字符串 "); // 将 QString 转换为 GBK 格式的 QByteArray 字符数组。 // QByteArray::data() 可以拿到 const char* 。 QByteArray gbk_s = QTextCodec::codecForName("gbk")->fromUnicode(s); // 然后再从 GBK 字符数组转换回 QString 。 QString s2 = QTextCodec::codecForName("gbk")->toUnicode(gbk_s); 有关文件 IO的编码处理 ● 事实上 Qt 读取文件可以用任何一种编码,只是默认以 codecForLocale而已。 ● 使用 QTextStream 可以通过文本方式读取 QFile ,而 QTextStream则可以设定使用的编码方式。 ● 就算文件名有中文也不怕。只要正确转换为 QString,剩 下的就交给 Qt吧! QFile file(QString::fromUtf8("中文名 .txt")); if (file.open(QIODevice::ReadOnly)) { QTextStream fin(&file); fin.setCodec(QTextCodec::codecForName("utf-8")); fin.readLine(); } 反而是 QObject::tr不应滥用 ● 可能有不少人随手写过这样的代码吧: tr("新建文本文档 .txt") ● 能用 tr轻易解决中文乱码,这似乎很方便。但是 tr绝不应 该用在这种地方!使用 tr标记的文本,可以被 Qt配套的工 具扫描出来,然后交给「精通各国外语的牛人」进行翻译。 ● 翻译完成之后, QObject::tr函数就会在已经加载的翻译文 件中,查找这个字符串的翻译。如果找到,就会用翻译好的 字符串替换原来的字符串。 ● 那么,文件名算什么「需要翻译的字符串」啊亲? QObject::tr的真正作用 恩,似乎问题都解决了? 其实本来我还有很多话题的 ● 比如在没有 Qt的情况下,怎么在 C++程序里正确处理 UTF-8。 ( Windows 环 境 下 面 使 用 MultiByteToWideChar 和 WideCharToMultiByte 这两个 API 。 Linux 嘛,这年头不用 zh_CN.UTF-8简直没脸见人了……) ● 比如 C++11的 UTF-8支持,还有 Qt 5.x的一些改变。 ● 比如在 Python里面怎么正确处理 UTF-8, GBK和 UTF-16。 (其实 Python 2.x编码处理更麻烦,因为 2.x对于 str和 unicode 两个类型会动不动自动转换,而且默认编码还改不了。有些函数 对于 str和 unicode有不同返回值,行为又诡异,会让你想哭!) ● 比如 HTML文件的编码, URL 的编码之类的。 不过,还是算了吧~ 页 1 页 2 页 3 页 4 页 5 页 6 页 7 页 8 页 9 页 10 页 11 页 12 页 13 页 14 页 15 页 16 页 17 页 18 页 19 页 20 页 21 页 22 页 23 页 24 页 25 页 26 页 27 页 28 页 29 页 30 页 31 页 32 页 33 页 34 页 35 页 36 页 37
/
本文档为【从此乱码是路人】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索