2.你的程序乱码了吗?

news2024/11/15 7:00:41

学习的动力不止于此:
在这里插入图片描述

1. 乱码

#include <QApplication>
#include <QLabel>
#include <QFont>
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();
}

兴冲冲地输入一段比如 “XXX 是大神” 的句子,结果却发现,显示的是乱码。

由于字符编码设置不当,导致应用程序无法正常显示文字,称之为乱码。

QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());

以之问老师,老师给你三行代码

事实上,这三行代码,是相当错误的打开方式!

看win7下的例子:
在这里插入图片描述
当我们使用非中文windows时:
在这里插入图片描述

一、究竟是为什么?

● 其实不仅仅是我们的程序,在其他很多地方都有乱码。
● 打开一个网页,结果显示出来的是不知所云的外星文字。
● 非英语国家的软件,曾经有过那么一段水火不容的历史。
● 玩过日文游戏的人,可能都接触过 AppLocale 这个神器。
● 还有清华计算机系BBS楼 9# 论坛分为 GBK 和 BIG5 两种编码环境。

二、是一个很复杂的历史问题

● 计算机只能存储二进制位。 8 个二进制位是 1 个字节。 1个字节可以表示 0 ~ 255 之间的任何一个数字。
● 文件,无论是「文本文件」还是「音乐文件」,或者是所谓的「二进制文件」,本质上都只是一连串 0 ~ 255 的数字。这个序列被称为字节流。
● 因此,我们眼中的「字符串」,在计算机看来,也不过是一个字节流而已。
● 表示「字符串」的过程,就是将字符映射为字节的过程。

三、发明了 ASCII 字符编码

英文字母很少,一个字节就能全部囊括,因此美国人只
发明了字节和英文字符之间的一一映射关系。

这就是 ASCII 。

后人们发现一个字节不够用,既然一个不够,我们就来俩。
● 在美国人的 ASCII 编码系统中, 128 ~ 255 之间的数字几乎没有使用。而凡是小于等于 127 的数字,二进制表示中首位都是 0 ;大于等于 128 的数字,首位都是 1 。
● 这个特性很快被得到了运用。一般的想法是,在字节流中,如果出现大于等于 0x80 的字符,则被认为(可能)是多字节编码的「前导字节」,需要同下一个字节一起构成完整的「字符」。
● 凭借这个方法,各个国家先后制定了自己的「多字节编码规则」。比如简体中文第一个国家编码,就是 GB2312 。
● 每个国家的文字编码「各自为政」,这导致不同国家
之间交换信息变得非常困难。传输文档之前要实现约
定双方使用的编码方式;当然这不是唯一的问题。
● 更大的问题在于,你甚至不可能在一篇文档里,同
时插入德语字母和中文汉字!于是你在打印一篇语
言混用的文章的时候,很可能需要将文章分批打印,
然后把他们全部粘起来?!

四、于是 Unicode 诞生了

● 事实上刚开始的时候, Unicode 编码曾经只有 65536 个字符空间。这个空间被称为「基本多文种平面」。用恒定的两个字节表示所有字符,这种编码方
式被称为 UCS-2 。
● 当 Unicode 字符超过 65536 之后,参考「多字节编码」,通过双字节扩展四字节的方式表示所有字符。这种编码方式被称为 UTF-16 。
● 为了便于网络传输和数据处理,不至于因为遇到“ \0” 而错误地以为文本结束,以及兼容 ASCII 码, UTF-8 被定义。 UTF-8 的每一个字符按规则编码为 1 ~ 4 任一字节组合。中文通常为 3 字节长。
● 当然,也有直接使用 4 字节编码所有字符的编码方式,被称为 UTF-32 或者UCS-4

五、 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 保存源文件的编码是
在这里插入图片描述
GBK 的源文件自然需要 GBK 解码
在这里插入图片描述
在非中文系统下就成了个悲剧
在这里插入图片描述

这个时代用 GBK 写程序就应该沙拉!!!

七、正确的打开方式

一个开发框架的生态系统可以长期、有效地支撑基于它开发的项目。Qt拥有超过一百万专注的用户群体。植根于开源社区,Qt的不断发展得益于世界各地乐于奉献的开发人员。Qt 公司的发展已经超过 了25年,并将继续成为您值得信赖的合作伙伴。
然后改变那三行代码……不,两行代码

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 的编码之类的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/341919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux文件隐藏属性(修改与显示):chattr和lsattr

文件除了基本的九个权限以外还有隐藏属性存在&#xff0c;这些隐藏属性对于系统有很大的帮助&#xff0c;尤其是系统安全&#xff08;Security&#xff09;上 chattr&#xff08;配置文件隐藏属性&#xff09; chattr 【-】【ASacdistu】文件或目录名称 选项与参数&#xff1a…

Visual Navigation(一):阅读三篇经典论文

文章目录前言一、Learning to Navigate in Cities Without a Map二、Unsupervised Predictive Memory in a Goal-Directed Agent三、Zero-Shot Imitation LearningImitation Learning:前言 研究生不读论文还是不行的呀&#xff0c;在这里结合下别人的总结等下一次组会吹水。 …

大客户市场:阿里云、腾讯云、华为云“贴身肉搏”

配图来自Canva可画 近年来&#xff0c;随着中国逐渐进入数字化经济快车道&#xff0c;国内企业数字化、智能化升级已是刻不容缓。而为了帮助自身或其他企业实现数字化转型升级&#xff0c;阿里、腾讯、百度、京东、字节、网易、华为等众多国内知名企业早在多年以前&#xff0c…

【Git学习】Git如何Clone带有Submodule的仓库?

文章目录一、问题描述二、解决问题三、参考链接四、解决问题4.1 下载主模块4.2 查看主模块的配置4.2 子模块的添加4.3 查看子模块的配置4.4 查看子模块的检出状态4.5 检出submodule4.6 再次查看.git/config4.7 重新打开Android Studio运行代码一、问题描述 在GitHub上下载了一…

Android12 Launcher3 最近任务客制化

实现的最终效果: 目录 修改图标位置+添加应用名称 代码实现: 图标控件的边距调整:

微信小程序 button按钮怎么触发事件? bindtap语法怎么使用?

在前端网页中我们需要触发一个事件如果按钮点击后调用函数&#xff0c;文本、图片、链接被点击后调用一个函数一个事件&#xff0c;我们都知道用click&#xff0c;可是微信小程序中的click是不存在的&#xff0c;他怎么才能和网页中一样的使用click的呢&#xff1f; 1.bindtap语…

编程思想-0x00架构

产生架构的原因&#xff1f; 1、代码均摊 将不同的代码进行分块&#xff0c;然后简历联系&#xff0c;低耦合、高内聚&#xff1b; 原则上&#xff1a;合理的App架构应该是合理分配每个类、结构体、方法、变量的存在都应该遵循单一职责的原则 2、便于测试 测试确保代码质量&…

【编程基础之Python】3、创建Python虚拟环境

【编程基础之Python】3、创建Python虚拟环境创建Python虚拟环境为什么需要虚拟环境Windows上的Anaconda创建虚拟环境conda 命令conda env 命令创建虚拟环境切换虚拟环境验证虚拟环境Linux上的Anaconda创建虚拟环境创建虚拟环境切换虚拟环境验证虚拟环境总结创建Python虚拟环境 …

性能优化方向

性能怎么样就看io的应用&#xff0c;网络和数据库要好好设计&#xff0c;能一次查出来就一次。 对外接口尽量不要多创建对象&#xff0c; 少用bean复制 少用getbean(.class) 缓存不要频繁操作&#xff0c;最好异步 循环不要调用数据库&#xff0c;调用接口最好批量 Compon…

UG NX二次开发(C#)-UIStyler-创建长方体

文章目录 1、前言2、UG NX自动的创建长方体界面3、在块样式编辑器中创建UI界面4、创建一个工程5、在创建按钮中添加代码6、调用dll7、结论1、前言 UG NX二次开发中,UIStyler是一种非常高效的开发方式,UG NX已经为我们提供了比较完善的UIStyler开发模板,只要通过拖动的方式就…

GAN系列基础知识

原始值函数 原始GAN的值函数是 minGmaxDV(D,G)Ex∼pdata(x)[logD(x)]Ez∼pz(z)[log(1−D(G(z)))]min_Gmax_DV(D,G) E_{x \sim p_{data}(x)}[logD(x)]E_{z \sim p_{z}(z)} [log(1-D(G(z)))]minG​maxD​V(D,G)Ex∼pdata​(x)​[logD(x)]Ez∼pz​(z)​[log(1−D(G(z)))] 其中Ex…

尚医通(十二)SpringCloud相关概念介绍 | 搭建Nacos服务

目录一、什么是微服务1、微服务的由来2、为什么需要微服务3、微服务与单体架构区别4、微服务本质5、什么样的项目适合微服务6、微服务开发框架7、什么是Spring Cloud8、Spring Cloud和Spring Boot是什么关系9、Spring Cloud相关基础服务组件10、Spring Cloud的版本二、Nacos1、…

XXL-JOB 极简入门

文章目录1 概述2 特性3 架构设计3.1设计思想3.2 系统组成3.3架构图3.4 高可用3.4.1 调度中心的高可用3.4.2 执行器的高可用4 搭建调度中心4.1 克隆源码4.2 初始化 XXL-JOB 表结构修改配置文件4.4 修改日志配置文件4.5 IDEA 启动调度中心4.6 编译源码4.7 命令行启动调度中心4.8 …

D32 Vue2 + Vue3 K124-K143

D32.Vue F21.创建vue3项目&#xff08;K124-K129&#xff09; 该笔记是从vue2过渡到vue3的&#xff0c;所以不会特别详细的介绍某些vue2学过的&#xff0c;主要介绍vue3新增的 1.Vue3快速上手 A. Vue3简介 1&#xff09;2020年9月18日&#xff0c;Vue.js发布3.0版本&…

高性能(一)

思维导图 一、负载均衡 1.概念 将用户请求分摊到不同服务器上处理&#xff0c;以提高系统整体的并发处理能力及可靠性。 如图&#xff1a;我们用到负载均衡&#xff0c;实现访问商品服务的请求的分流。 负载均衡是一种常用且简单的提高系统并发和可靠性的手段&#xff0c;单…

MySQL入门篇-MySQL 二进制日志binlog介绍

MySQl binlog介绍 binlog的作用 逻辑日志,记录的是数据库内部的所有变动&#xff08;sql语句 行的改变&#xff09; server层日志&#xff0c;binlog不仅仅记录innodb的变动&#xff0c;也记录myisam存储引擎的变动。 innodb redo 是存储引擎层&#xff0c;和binlog不是一层&…

spark02-内存数据分区切分原理

代码&#xff1a;val conf: SparkConf new SparkConf().setMaster("local[*]").setAppName("wordcount") val scnew SparkContext(conf) //[1] [2,3] [4,5] val rdd: RDD[Int] sc.makeRDD(List(1,2,3,4,5),3) //将处理的数据保存分区文件 rdd.saveAsText…

【PTA Advanced】1152 Google Recruitment(C++)

目录 题目 Input Specification: Output Specification: Sample Input 1: Sample Output 1: Sample Input 2: Sample Output 2: 思路 代码 题目 In July 2004, Google posted on a giant billboard along Highway 101 in Silicon Valley (shown in the picture below)…

清除 git 所有历史提交记录,使其为新库

清除 git 所有历史提交记录&#xff0c;使其为新库需求方案需求 基于以前的仓库重新开发&#xff0c;这样可保留以前的配置等文件&#xff0c;但是需要删除全部的历史记录、tag、分支等。 方案 创建新的分支 使用 --orphan 选项&#xff0c;可创建1个干净的分支&#xff08;无…

设置测试用例的具体方法

文章目录一、等价类分区/分块的概念等价类的划分二、边界值三、因果图(判定表)四、场景设计法五、错误猜测法总结一、等价类 用户的密码为6~18位,测试的时候使用到的测试数据是什么? 穷举法,6,7,8,9,10…18全部都测试一边,可以 但是将范围改成6~1000位,穷举法就不可取了 分区/…