Qt字符编码

目前字符编码有以下几种:

1、UTF-8

        UTF-8编码是Unicode字符集的一种编码方式(CEF),其特点是使用变长字节数(即变长码元序列、变宽码元序列)来编码。一般是1到4个字节,当然,也可以更长。

2、UTF-16

        UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为 "storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元, 长度为2 Byte)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。UTF-16是2字节或4字节存储,英文也是2字节。详细请参考文章

UTF-8 与 UTF-16编码详解-CSDN博客

3、GBK,GB2312  

何为GBK,何为GB2312,与区位码有何渊源?

区位码是早些年(1980)中国制定的一个编码标准,如果有玩过小霸王学习机的话,应该会记得有个叫做“区位”的输入法(没记错的话是按F4选择)。就是打四个数字然后就出来汉字了,什么原理呢。请看下面的区位码表,每一个字符都有对应一个编号。其中前两位为“区”,后两位为“位”,中文汉字的编号区号是从16开始的,位号从1开始。前面的区号有一些符号、数字、字母、注音符号(台)、制表符、日文等等。

而GB2312编码就是基于区位码的,用双字节编码表示中文和中文符号。一般编码方式是:0xA0+区号,0xA0+位号。如下表中的 “安”,区位号是1618(十进制),那么“安”字的GB2312编码就是 0xA0+16  0xA0+18 也就是 0xB0 0xB2 。根据区位码表,GB2312的汉字编码范围是0xB0A1~0xF7FE

区位码表节选

可能大家注意到了,区位码里有英文和数字,按道理说是不是也应该是双字节的呢。而一般情况下,我们见到的英文和数字是单字节的,以ASCII编码,也就是说现代的GBK编码是兼容ASCII编码的。比如一个数字2,对应的二进制是0x32,而不是 0xA3 0xB2。那么问题来了,0xA3 0xB2 又对应到什么呢?还是2(笑)。注意看了,这里的2跟2是不是有点不太一样?!确实是不一样的。这里的双字节2是全角的二,ASCII的2是半角的二,一般输入法里的切换全角半角就是这里不同。

如果留意过早些年的手机(功能机),会发现人名中常见的“燊”字是打不出来的。为什么呢?因为早期的区位码表里面并没有这些字,也就是说早期的GB2312也是没有这些字的。到后来的GBK(1995)才补充了大量的汉字进去,当然现在的安卓苹果应该都是GBK字库了。再看看这些补充的汉字的字节码 燊 0x9F 0xF6 。和前面说到的GB2312不同,有的字的编码比 0xA0 0xA0 还小,难道新补充的区位号还能是负的??其实不然,这次的补充只补充了计算机编码表,并没有补充区位码表。也就是说区位码表并没有更新,用区位码打字法还是打不出这些字,而网上的反向区位码表查询也只是按照GBK的编码计算,并不代表字与区位号完全对应。时代的发展,区位码表早已经是进入博物馆的东西了。

Big5是与GB2312同时期的一种台湾地区繁体字的编码格式。后来GBK编码的制定,把Big5用的繁体字也包含进来(但编码不兼容),还增加了一些其它的中文字符。细心的朋友可能还会发现,台湾香港用的繁体字(如KTV里的字幕)跟大陆用的繁体字还有点笔画上的不一样,其实这跟编码无关,是字体的不同,大陆一般用的是宋体楷体黑体,港澳台常用的是明体(鸟哥Linux私房菜用的是新細明體)。GBK总体编码范围为0x8140~0xFEFE,首字节在 0x81~0xFE 之间,尾字节在 0x40~0xFE 之间,剔除 xx7F 一条线。详细编码表可以参考这个列表。微软Windows安排给GBK的code page(代码页)是CP936,所以有时候看到编码格式是CP936,其实就是GBK的意思。2000年和2005年,国家又先后两次发布了GB18030编码标准,兼容GBK,新增四字节的编码,但比较少见。

GBK编码字符有一字节和双字节编码,00–7F范围内是第一个字节,和ASCII保持一致,此范围内严格上说有96个文字和32个控制符号。之后的双字节中,前一字节是双字节的第一位。总体上说第一字节的范围是81–FE(也就是不含80和FF),第二字节的一部分领域在40–7E,其他领域在80–FE。

4、ANSI

用Notepad++创建一个文本文件text.txt,其默认编码格式为ANSI(乍看之下,还以为是ASCII呢),输入汉字居然不是乱码:

保存为test.txt,发送给你美国的同事Bob。他也用Notepad++,不幸的是,却发现你的文件内容是这样的:

也许你会认为:你用的是中文系统,能正常显示中文;他用的是英文系统,不能显示中文!

这么想,好像很有道理呢!

但是再细想一下:一个系统显示乱码,说明它不支持这种编码格式(或者解码方式不对)。难道英文系统不支持ANSI?难道ANSI是一种中文编码?

如果你身边有一个韩文系统,也装一个Notepad++,默认还是ANSI编码,你可以输入“한국어”,发现也能正常显示:
 


但是你要输入“汉字”可能就会发现是乱码了...

通过这个反例,就可以说明ANSI不是一种中文编码。那么,ANSI到底是什么编码?

用十六进制编辑器打开内容为“汉字”的test.txt文件:
 


你会发现:其中baba和d7d6正好是“汉”和“字”两个字的GBK编码值。

同样,用十六进制编辑器打开内容为“한국어”的test.txt文件:
 


你会发现:其中c7d1、b1b9和beee正好是“한”、“국”和“어”三个字符的EUC-KR编码值。

由此可以看出:其实ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。你的美国同事Bob的系统中ANSI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而你的系统中(“汉字”正常显示)ANSI编码其实是GBK编码,而韩文系统中(“한국어”正常显示)ANSI编码其实是EUC-KR编码。

5、QString中的编码

        QString中只存放unicode的utf16编码的字符串,内部用QChar(short)类型的指针进行保存。如果非要使用utf-8或ansi编码的字符串操作类,可以使用QLatin1String类。也可以考虑使用QByteArray类甚至std::string。

       char*变量在内存中存放的字符串默认编码,与编译器参数 execution-charset有关,而vs2015及以下编译器默认为 "/execution-charset=GB2312",也就是char*变量内存中保存时使用ansi(具体为GB2312)编码,vs2022默认为 "/execution-charset=UTF-8",gcc或类gcc编译器默认为 "-fexec-charset=UTF-8",特就是char*使用unicode的utf8编码。可以通过在字符串前加u8强制编译器对某个char*变量在内存中保存时采用unicode的utf8编码。
        char*转换成QString,一定会做一次字符编码的转码!!!通过QString(const char*)构造的QString对象,char*字符串会被QString强制当成unicode的 utf8编码,这是QString代码不可更改的,并隐式的将这个强制当做unicode 的utf8编码的字符串转换成unicode的utf16编码的字符串。vs编译器 的 execution-charset 默认 为ansi编码,存放的编码为ansi编码,如果你qt工程采用vs2015编译器或以下编译器,这时候强制当做unicode的utf8转换成QString,就一定会乱码,(所以这个时候最好设置"/execution-charset=UTF-8"的编译器参数)。QString 官方不建议使用从char*转QString的构造函数。所以在这个构造函数前加了QT_ASCII_CAST_WARN 宏开关和宏提示。QString中所有的从char*转换到QString的构造函数 或者 由char*隐式转换到QString的函数 或者 参数中含有char*的非static函数 都是隐式调用QString::fromUtf8(char*) 这个静态函数 进行字符编码的转换的。从QByteArray转QString 与 char*转QString 是一样,也会出现同样的问题。

从char*转到QString ,QString有提供很多的static类型的转码函数,qt建议通过调用这些函数进行显示的编码转换。

D:\Qt\Qt5.12.0\5.12.0\mingw73_64\include\QtCore\qstring.h
    static inline QString fromLatin1(const QByteArray &str)//从ascii编码转unicode的utf16编码
    { return str.isNull() ? QString() : fromLatin1(str.data(), qstrnlen(str.constData(), str.size())); }
    static inline QString fromUtf8(const QByteArray &str)  //从unicode8的编码转换成unicode的utf16编码
    { return str.isNull() ? QString() : fromUtf8(str.data(), qstrnlen(str.constData(), str.size())); }
    static inline QString fromLocal8Bit(const QByteArray &str) //从local编码转换虫unicode的utf16编码
    { return str.isNull() ? QString() : fromLocal8Bit(str.data(), qstrnlen(str.constData(), str.size())); }
    static QString fromUtf16(const ushort *, int size = -1);   //从unicode的utf16编码转unicode的utf16编码,可以在字符串前存放BOM来指定输入的字符串字节序,否则采用系统默认字节序
    static QString fromUcs4(const uint *, int size = -1);      //从unicode的utf32编码转unicode的utf16编码,可以在字符串前存放BOM来指定输入的字符串字节序,否则采用系统默认字节序
#if defined(Q_COMPILER_UNICODE_STRINGS)
    static QString fromUtf16(const char16_t *str, int size = -1)
    { return fromUtf16(reinterpret_cast<const ushort *>(str), size); }
    static QString fromUcs4(const char32_t *str, int size = -1)
    { return fromUcs4(reinterpret_cast<const uint *>(str), size); }
#endif
QString::fromUtf8(char*) 转码失败是不会给提示的,但是会将不认识的字节 转成 0xfffd。
如果你将ansi编码的字符串传入, 比如ansi编码的 "你好" 传入,其ansi(GB2312)编码为0xC4E3 0xBAC3 ,会得到由四个0xfffd的QChar组成的QString。

下面的案例中,使用windows下qt5.12+vs2015编译器的场景,采用默认的excution-charset(默认值为GB2312)和source-charset(默认值为GB2312)编译器参数,源文件编码为带BOM的utf8(vs编译器能通过BOM识别到文件为utf8编码,并自动将source-charset设置为utf8编码),QTextCodec为 system编码(在我电脑上也就是ansi(GB2312)),excution-charset为默认的ansi(GB2312)编码。

代码中QString类型的str1和str2都存在隐式地将ansi编码的字符串通过fromutf8() 转变成utf16编码的字符串,utf8并不识别ansi编码的字符串,存在转码错误,且刚好"你好"中的每个字节在utf8中都是非法的,导致char数组变量中的每个字节都变成值为0xfffd的占两个字节的QChar类型数据。 当然,主要问题还是qt中可能存在大量隐式的将char*赋予QString的地方。比如我们常用的qDebug中就有。各种使用char*的地方都可能存在隐式的将chai*转QString而存在字符编码转码的隐患!

测试代码
int main(int argc, char *argv[])
{
    char cstr1[]="你好c1";
    char cstr2[]=u8"你好c2";
    wchar_t cstr3[]=L"你好c3";
    QString str1("你好1");      //存在隐式地将gb2312转换成unicode的utf16
    QString str2;
    str2+="你好2";              //存在隐式地将gb2312转换成unicode的utf16
    qDebug()<<"你好"<<endl;     //qDebug内部存在隐式的将gb2312转换成unicode的utf16
    //显示将gb2312转QString所需的utf16。qt推荐的用法。
    QString str3=QString::fromLocal8Bit("你好3");
    //显示将Utf8转QString所需的utf16。qt推荐的用法。
    QString str4=QString::fromUtf8(u8"你好4");
    QString str5=QString::fromLocal8Bit(cstr1);
    QString str6=QString::fromUtf8(cstr2);
    ushort buffer1[6]={};
    ushort buffer2[6]={};
    ushort buffer3[6]={};
    ushort buffer4[6]={};
    memcpy(buffer1,str1.data(),str1.length()*2);
    memcpy(buffer2,str2.data(),str2.length()*2);
    memcpy(buffer3,str3.data(),str3.length()*2);
    memcpy(buffer4,str4.data(),str4.length()*2);
 
    //设置控制台接收ansi(gb2312)编码的字符串。936是windows中GB2312字符编码的代码。
    system("chcp 936");
    cout<<cstr1<<endl;
 
    qDebug().noquote()<<str1;
    qDebug().noquote()<<str2;
    qDebug().noquote()<<str3;
    qDebug().noquote()<<str4;
    qDebug().noquote()<<str5;
    qDebug().noquote()<<str6;
 
 
    return 0;
}
 

                     
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/qiushangren/article/details/136617718

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/jackgo73/article/details/130225319

同一个编码文件里,怎么区分ASCII和中文编码呢?从ASCII表我们知道标准ASCII只有128个字符,0~127即0x00~0x7F(0111 1111)。所以区分的方法就是,高字节的最高位为0则为ASCII,为1则为中文。


笔者之前写过utf-8的博客【点击】
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/hherima/article/details/50801360

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

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

相关文章

postman 获取登录接口中的返回token并设置为环境变量的方法 postman script

postman是一个比较方便的API开发调试工具&#xff0c; 我们在访问API时一般都需要设置一个token来对服务进行认证&#xff0c; 这个token一般都是通过登录接口来获取。 这个postman脚本放到登录接口的sctipt--> post-response里面即可将登陆接口中返回的token值设置到postma…

使用Django REST framework构建RESTful API

使用Django REST framework构建RESTful API Django REST framework简介 安装Django REST framework 创建Django项目 创建Django应用 配置Django项目 创建模型 迁移数据库 创建序列化器 创建视图 配置URL 配置全局URL 配置认证和权限 测试API 使用Postman测试API 分页 过滤和排序…

消息队列面试——打破沙锅问到底

消息队列的面试连环炮 前言 你用过消息队列么&#xff1f;说说你们项目里是怎么用消息队列的&#xff1f; 我们有一个订单系统&#xff0c;订单系统会每次下一个新订单的时候&#xff0c;就会发送一条消息到ActiveMQ里面去&#xff0c;后台有一个库存系统&#xff0c;负责获取…

Rust 力扣 - 1493. 删掉一个元素以后全为 1 的最长子数组

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 本题我们能转换成求只包含一个0的子数组的最长长度 如果数组中不存在0&#xff0c;则结果为数组长度减一 我们使用一个left指针指向子数组的左边界&#xff0c;然后我们遍历子数组的右边界&#xff0c;我们记录…

在 Windows 系统上,在两台机器上测试 MySQL 集群实现实时备份的基本步骤:

在两台机器上测试 MySQL 集群实现实时备份的基本步骤&#xff1a; 一、环境准备 机器配置 确保两台机器&#xff08;假设为服务器 A 和服务器 B&#xff09;能够互相通信&#xff0c;例如它们在同一个局域网内&#xff0c;并且开放了 MySQL 通信所需的端口&#xff08;默认是 3…

常见的开源软件许可证及其应用案例

目录 引言 开源的定义 开源许可证的种类 常见的开源许可证及其应用案例 结论 引言 开源软件在过去几十年中迅速发展&#xff0c;已经成为软件开发的重要组成部分。开源不仅仅是一种技术模式&#xff0c;更是一种文化和社区精神。本文将详细介绍开源的定义、开源许可证的种…

校招回顾 | “青春不散场,梦想正起航”,极限科技(INFINI Labs)亮相湖北工业大学 2025 秋季校园招聘会

10 月 31 日&#xff0c;极限科技&#xff08;INFINI Labs&#xff09; 受邀参加 湖北工业大学 2025 届秋季校园招聘会&#xff0c;这不仅是一次与满怀激情的青年学子们的深度碰撞&#xff0c;更是一场关于青春与未来的美好邂逅。让我们一起回顾校招现场的精彩瞬间&#xff0c;…

基于python的机器学习(一)—— 基础知识(Scikit-learn安装)

目录 一、机器学习基础 1.1 机器学习概述 1.2 监督学习、无监督学习和强化学习 1.3 聚类、分类、回归、标注 1.3.1 聚类 1.3.2 分类 1.3.3 回归 1.3.4 标注 1.4 机器学习、人工智能和数据挖掘 1.5 机器学习的三个要素 二、Scikit-learn 机器学习库 2.1 Scikit-lea…

第五篇: 使用Python和BigQuery进行电商数据分析与可视化

使用Python和BigQuery进行电商数据分析与可视化 大数据分析对于电商业务的洞察至关重要。在这篇文章中&#xff0c;我们将使用Python结合Google BigQuery来分析电商数据集&#xff0c;以最畅销商品和平均订单价格最高的前10位客户为主题&#xff0c;展示如何通过数据可视化提供…

基于SpringBoot+Vue的快递物流信息查询系统设计与实现【前后端分离】

基于SpringBootVue的快递物流信息查询系统设计与实现 摘要 随着电子商务的快速发展&#xff0c;快递物流系统的重要性愈发突出。针对用户对快递信息的实时查询需求&#xff0c;本系统结合Spring Boot和Vue技术&#xff0c;设计并实现了一个高效、易用的快递物流信息查询系统。系…

开源免费的API网关介绍与选型

api网关的主要作用 API网关在现代微服务架构中扮演着至关重要的角色&#xff0c;它作为内外部系统通信的桥梁&#xff0c;不仅简化了服务调用过程&#xff0c;还增强了系统的安全性与可管理性。例如&#xff0c;当企业希望将内部的服务开放给外部合作伙伴使用时&#xff0c;直…

WPF+MVVM案例实战(十七)- 自定义字体图标按钮的封装与实现(ABC类)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1、案例效果1、按钮分类2、ABC类按钮实现1、文件创建2、字体图标资源3、自定义依赖属性4、按钮特效样式实现 3、按钮案例演示1、页面实现与文件创建2、依赖注入3 运…

使用MongoDB Atlas构建无服务器数据库

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用MongoDB Atlas构建无服务器数据库 MongoDB Atlas 简介 注册账户 创建集群 配置网络 设置数据库用户 连接数据库 设计文档模式…

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏 目录 文章目录 【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏目录摘要研究背景问题与挑战如何解决创新点算法模型实验效果代码推荐阅读指数&…

P9220 「TAOI-1」椎名真昼

P9220 「TAOI-1」椎名真昼 考点&#xff1a;博弈论、拓扑、强连通分量。 难度&#xff1a; 提高/省选- 。 题意&#xff1a; ​ Alice 和 Bob 玩游戏&#xff0c;给定一个有向图&#xff0c;每个点有初始颜色&#xff08;黑/白&#xff09;。 ​ 双方轮番操作一次&#xf…

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

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

例行性工作

1、单一执行------at-----仅处理执行一次就结束了 1.1工作过程 /etc/at.allow&#xff0c;写在该文件的人可以使用at命令/etc/at.deny&#xff0c;黑名单两个文件如果都不存在&#xff0c;只有root能使用 1.2命令详解------命令格式&#xff1a;at [参数] [时间] 2、循环执行…

使用Kafka构建大规模消息传递系统

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Kafka构建大规模消息传递系统 引言 Kafka 简介 安装 Kafka 创建主题 生产者 消费者 高级特性 分区 持久化 消费者组 消息确认…

【sqlmap使用】

sqlmap简介 sqlmap 目录结构 sqlmap常用参数 sqlmap实现注入 测试注入点&#xff0c;检测到注入点后&#xff0c;直接爆数据库名 python sqlmap.py –u http://172.16.12.2/7/9/strsql.php --data "usernameadmin" --dbs注意sqlmap在使用过程中可能会出现几个需要…

【java】java的基本程序设计结构07-字符串

字符串 1. 创建字符串 最简单的&#xff1a; String str "hello"; 用构造函数创建字符串&#xff1a; String str2new String("hello"); String 创建的字符串存储在公共池中&#xff0c;而 new 创建的字符串对象在堆上&#xff1a; 注意: String 类…