由中文乱码引来的一系列学习——Qt

前言

解决中文引起的乱码,并不难,网上一搜就有好几个方法任君选择,但是解决乱码的这些方法的原理是什么,我一直没太明白。

这次项目需要在Android环境下运行,而根据Qt跨平台的特性,我一般是在Windows环境下(MSVC2019_32bit)先进行测试:Windows环境下是是使用预编译(# pragma execution_character_set("utf-8"))解决乱码的,而我在Android下并没有使用任何措施防止中文乱码,但是Android下并没有出现中文乱码的情况,这个是为什么呢?带着这个疑问,我开始在网上各种学习此类知识,在此记录下。

Android没有出现中文不乱码的原因

在Android中,默认的字符编码通常是UTF-8,这是因为Android的API和框架大部分都是使用Java编写的,而Java字符串和字符编码默认使用UTF-8。

 

Windows中文乱码的原因和解决方案

Windows中文乱码的原因

整体来说,编译器msvc默认源文件的中文为gbk(ANSI),但是QString处理时会按utf-8解析,这样就会用utf-8解析gbk的,导致编码错误。

详细分析如下:

 一般情况下,都是使用QString对字符进行存储,进而在控件中展示。比如

ui->label->setText("中文标签");

等同于

    const QString& text = QString("中文标签");ui->label->setText(text);

QString类存储的是Unicode字符,帮助文档对QString的构造函数也说了对于传入的常量字符串指针会通过 fromUtf8() 方法转换为Unicode。

QString::QString(const char *str)
Constructs a string initialized with the 8-bit string str. The given const char pointer is converted to Unicode using the fromUtf8() function.

使用 fromUtf8() 进行转换,也说明了Qt 默认传入的是 utf-8 格式的编码,但此处真的是 utf-8 格式的编码吗?并不是,MSVC默认是ANSI编码,最直观的是可以看下构建生成的.obj文件(cl.exe(微软的C编译器)来编译源代码,并生成.obj文件),可以看出编译生成的文件编码格式是ANSI,可以找到“中文标签”,并未乱码。

所以由于“中文标签” 在此环境下是ANSI编码,而Qt却默认utf-8格式的,使用错误的方法将其转换为Unicode。

Windows解决中文乱码的方案

这就得出解决乱码的方案,可以从几个不同方向进行解决:

使用正确的编码方法进行转换

  • 使用QString::fromLocal8Bit(告诉Qt用本地方式转换)
    const QString& text = QString::fromLocal8Bit("中文标签");ui->label->setText(text);

 查看QString::fromLocal8Bit的源代码是使用QTextCodec实现的,所以也可以自己直接调用QTextCodec。

QString QString::fromLocal8Bit_helper(const char *str, int size)
{if (!str)return QString();if (size == 0 || (!*str && size < 0)) {QStringDataPtr empty = { Data::allocate(0) };return QString(empty);}
#if QT_CONFIG(textcodec)if (size < 0)size = qstrlen(str);QTextCodec *codec = QTextCodec::codecForLocale();if (codec)return codec->toUnicode(str, size);
#endif // textcodecreturn fromLatin1(str, size);
}
  • 使用QTextCodec
    QTextCodec *codec = QTextCodec::codecForLocale();ui->label->setText(codec->toUnicode("中文标签"));

设置编译器的编码方式为utf-8  

  • 使用杂记(#pragma execution_character_set( “utf-8” ))标记此处编码

        指定用于字符串和字符文本的执行字符集。 用 u8 前缀标记的文本不需要此指令。 

#pragma execution_character_set( “utf-8” )

execution_character_set pragma | Microsoft Learn

但是官方文档对此用法不推荐:

此编译器指令在 Visual Studio 2015 Update 2 及更高版本中已过时。 建议将 /execution-charset:utf-8 或 /utf-8 编译器选项与包含扩展字符的窄字符和字符串文本的 u8 前缀一起使用。 

  • 设置C/C++命令行选项 /utf-8

        将源字符集和执行字符集指定为 UTF-8。

        

        更多说明见/utf-8 (将源和执行字符集设置为 UTF-8) | Microsoft Learn 

  通过此设置,可以在看一下编译生成的obj 文件,可以看到在utf-8编码格式下查看,“中文标签”并没有乱码。

使用前缀标记文本为Unicode

  • 直接使用前缀u8
ui->label->setText(u8"中文标签");

 c++11 增加了对Unicode的支持:

C++11引入以下两种新的内置数据类型来存储不同编码长度的Unicode数据:

  • char16_t: 用于存储UTF-16编码的Unicode数据。
  • char32_t: 用于存储UTF-32编码的Unicode数据。

至于UTF-8编码的Unicode数据,C++11还是使用8字节宽度的char类型的数组来保存。而char16_t和char32_t的长度则犹如其名称所显示的那样,长度分别为16字节和32字节,对任何编译器或者系统都是一样的。此外,C++11还定义了一些常量字符串的前缀。在声明常量字符串的时候,这些前缀声明可以让编译器使字符串按照前缀类型产生数据。事实上,C++11一共定义了3种这样的前缀:

u8表示UTF-8编码

u表示为UTF-16编码

U表示为UTF-32编码

  • 使用Qt的宏 QStringLiteral(使用前缀u)
ui->label->setText(QStringLiteral("中文标签"));

QStringLiteral是一个从字符串常量创建QString对象的宏。

宏在编译时,从字符串文字生成QString数据,QString的内部数据将在编译时生成,在运行时不会发生任何转换或内存分配,使用QStringLiteral来代替C++中的双重数值传递将会在编译的时候显著的提升运行效率。

QStringLiteral的源码如下,从中看出使用了前缀u 标记字符串常量。

#define QT_UNICODE_LITERAL(str) u"" str
#define QStringLiteral(str) \([]() noexcept -> QString { \enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \static const QStaticStringData<Size> qstring_literal = { \Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \QT_UNICODE_LITERAL(str) }; \QStringDataPtr holder = { qstring_literal.data_ptr() }; \return QString(holder); \}()) \

关于源字符集和执行字符集的说明

  • 源字符集: 源文件字符集是指源文件保存时按源字符集编码方式编码后的字符集。VS2019源字符集编码格式默认是GBK格式,在利用VS编写代码时,源代码会自动编码为GBK字符集。
  • 执行字符集: 程序运行时所使用的字符集,编译器会将源字符集先按照源字符集编码方式进行解码,再将解码后得到的字符按照执行字符集编码方式编码为执行字符集。执行字符集一般默认使用Windows系统本地字符编码,若是简体中文系统,则是GBK或GB2312字符集。

 

Unicode in Qt

在Qt官方文章

Unicode in Qt | Qt 5.15

中说:

Unicode is the standard for encoding text in almost all languages spoken in the world. It is nowadays used as the native encoding for text on most modern operating systems. The major exception is Microsoft Windows that still has a dual system supporting code pages and Unicode for applications.

翻译过来是:

Unicode是用于编码世界上几乎所有语言的文本的标准。如今,它已成为大多数现代操作系统的默认编码方式。唯一的例外是微软Windows系统,它对于应用程序仍然有双系统去支持代码页和Unicode。

这句话,也显出Windows系统与其他操作系统的 区别,也是存在中文乱码的原因。

Qt对Unicode提供的支持:

In Qt, and in most applications that use Qt, most or all user-visible strings are stored using Unicode. Qt provides:

  • Translation to/from legacy encodings for file I/O: see QTextCodec and QTextStream.
  • Support for locale specific Input Methods and keyboards.
  • A string class, QString, that stores Unicode characters, with support for migrating from C strings including fast translation to and from UTF-8, ISO8859-1 and US-ASCII, and all the usual string operations.
  • Unicode-aware UI controls.
  • Unicode compliant text segmentation (QTextBoundaryFinder)
  • Unicode compliant line breaking and text rendering 

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

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

相关文章

浅析数据库缓存一致性问题

在真实的业务场景中&#xff0c;我们的业务的数据——例如订单、会员、支付等——都是持久化到数据库中的&#xff0c;因为数据库能有很好的事务保证、持久化保证。但是&#xff0c;正因为数据库要能够满足这么多优秀的功能特性&#xff0c;使得数据库在设计上通常难以兼顾到性…

element plus el-form自定义验证输入框为纯数字函数

element plus 的el-form 使用自定义验证器&#xff0c;验证纯数字&#xff0c;禁止输入小数、中文、字母、特殊符号。input的maxlength为最大输入多少位长度 效果图 <el-form ref"dataFormRef" :model"dataForm" :rules"dataRules" label-w…

jira如何查看历史Sprint

方法一&#xff1a;通过看板模块查看历史 Sprint 进入看板模块 在项目的看板中&#xff0c;找到并点击“模块项”。在右侧历史记录中选择一个模块项。 查看 Sprint 历史 进入模块项界面后&#xff0c;点击“搜索”按钮旁边的“更多”下拉菜单。勾选“Sprint”选项&#xff0c;…

阿里云 DataWorks 正式支持 SelectDB Apache Doris 数据源,实现 MySQL 整库实时同步

SelectDB 是由飞轮科技基于 Apache Doris 内核打造的现代化数据仓库&#xff0c;支持大规模实时数据上的极速查询分析。 通过实时、统一、弹性、开放的核心能力&#xff0c;能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实…

OV(企业型)通配符域名SSL证书

SSL证书是由CA机构签发的&#xff0c;相信这一点大家都知道&#xff0c;然而目前全世界兼容性可以达到99%机构仅有&#xff1a;GlobalSign、DigiCert、Sectigo、Certum&#xff0c;最后一家还是勉强。 SSL证书选择OV&#xff08;国内有人称之为企业型&#xff09;其实就是实名…

软考系统分析师知识点三五: 考前强记知识点

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间&#xff1a;11月9日。 倒计时&#xff1a;2天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第四阶段&#xff1a;考前强记知识点。 考前强记知识点 系统分析主要任…

基础算法——排序算法(冒泡排序,选择排序,堆排序,插入排序,希尔排序,归并排序,快速排序,计数排序,桶排序,基数排序,Java排序)

1.概述 比较排序算法 算法最好最坏平均空间稳定思想注意事项冒泡O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)Y比较最好情况需要额外判断选择O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)N比较交换次数一般少于冒泡堆O( n l o g n nlogn nlogn)O( n l o g n nlogn nlogn)O( n l…

探索 Python 视频编辑新纪元:MoviePy库的神秘面纱

文章目录 探索 Python 视频编辑新纪元&#xff1a;MoviePy 库的神秘面纱第一部分&#xff1a;背景介绍第二部分&#xff1a;MoviePy 是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;简单的库函数使用方法第五部分&#xff1a;结合场景使…

计算机网络:网络层 —— 多播路由选择协议

文章目录 多播路由选择协议多播转发树构建多播转发树基于源树的多播路由选择建立广播转发树建立多播转发树 组共享树的多播路由选择基于核心的生成树的建立过程 因特网的多播路由选择协议 多播路由选择协议 仅使用 IGMP 并不能在因特网上进行IP多播。连接在局域网上的多播路由…

Jenkins插件使用问题总结

Git Push插件 插件介绍 主要是用于git推送代码到远程仓库中使用&#xff0c;插件地址 pipeline中使用 官方说明中只有一句代码gitPush(gitScm: scm, targetBranch: env.BRANCH_NAME, targetRepo: origin) 流水线语法中也做的不齐全所以一开始我老是设置错&#xff0c;导致代…

【命令操作】Linux三剑客之awk详解 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【命令操作】Linux三剑客之awk详解 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天带来一篇关于Linux三剑客之awk命令详解的文章。在文本处理工具中&#xff0c;awk以其强大的文本筛选、格式化和数据处理功能而闻名。它能够在处理结构化…

操作系统概念(一)——IOMMU学习

系列文章目录 提示&#xff1a;本系列主要记录工作过程中遇到的操作系统基础概念以及工作原理 第一章 操作系统之IOMMU 文章目录 系列文章目录1. 设备访问内存的几种主要方式1.1 传统的 I/O 访问&#xff08;程序控制 I/O&#xff09;1.2 直接内存访问&#xff08;DMA&#xf…

计算机网络:网络层 —— IP 多播技术

文章目录 基本概念IP多播地址和多播组 IP多播的类型硬件多播将IPv4多播地址映射为多播MAC地址 基本概念 多播&#xff08;Multicast&#xff0c;也称为组播&#xff09;是一种实现“一对多”通信的技术&#xff0c;允许一台或多台主机&#xff08;多播源&#xff09;发送单一数…

windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576

问题描述 我目前的环境是&#xff1a; 编辑器&#xff1a; Microsoft Visual Studio Community 2022 (64 位) 运行的脚本是ffmpeg自带的remux样例&#xff0c;只不过我想用c语言执行这个样例。在执行的过程中报错如下图&#xff1a; C4576 后跟初始值设定项列表的带圆括…

翻译工具开发技术笔记:《老挝语翻译通》app支持语音识别翻译功能,怎么提高语音识别的准确度呢?

《老挝语翻译通》app是一款专为老挝语翻译设计的免费工具&#xff0c;支持文本翻译、老挝文OCR文字识别提取、文字转语音。这款工具以其技术优势和用户友好的界面&#xff0c;为用户提供了便捷的老挝语翻译体验。 技术特点 文本翻译&#xff1a;支持双语输入&#xff0c;提供精…

Linux系统每日定时备份mysql数据

一、创建存储脚本的文件夹 创建文件夹&#xff0c;我的脚本放在/root/dbback/mysql mkdir ... cd /root/dbback/mysql 二、编写脚本 vi backup_mysql.sh 复制脚本内容 DB_USER"填写用户名" DB_PASSWORD"填写密码" DB_NAME"数据库名称" # …

MySQL基础-单表查询

语法 select [distinct] 列名1&#xff0c;列名2 as 别名... from数据表名 where组前筛选 group by分组字段 having组后筛选 order by排序的列 [asc | desc] limit 起始索引&#xff0c;数据条数 测试数据 # 建测试表 create table products (id int primary key a…

【Linux】Linux管道揭秘:匿名管道如何连接进程世界

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.什么是管道 &#xff1f;2. 管道的类型2.1 匿…

前端学习Day13 CSS盒子的定位(固定定位篇“附练习”)

一、固定定位 固定定位 &#xff08;position:fixed&#xff09;其实是绝对定位的子类别&#xff0c;一个设置了 position:fixed 的元素是相对于视窗固定的&#xff0c;就算页面文档发生了滚动&#xff0c;它也会一直待在相同的地方。 ⚠️&#xff1a;固定定位会脱离文档流。…

Linux云计算 |【第五阶段】CLOUD-DAY9

主要内容&#xff1a; Metrics资源利用率监控、存储卷管理&#xff08;临时卷ConfitMap、EmptyDir、持久卷HostPath、NFS(PV/PVC)&#xff09; 一、Metrics介绍 metrics是一个监控系统资源使用的插件&#xff0c;可以监控Node节点上的CPU、内存的使用率&#xff0c;或Pod对资…