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.xdnf.cn/news/5996.html

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

相关文章

微服务设计模式 - 网关路由模式(Gateway Routing Pattern)

微服务设计模式 - 网关路由模式&#xff08;Gateway Routing Pattern&#xff09; 定义 网关路由模式&#xff08;Gateway Routing Pattern&#xff09;是微服务架构中一种非常重要的设计模式&#xff0c;主要用于在客户端和微服务之间提供一个中间层。这一模式通过中央网关路…

【Axure高保真原型】PDF阅读器

今天和大家分享PDF阅读器的原型模板&#xff0c;我们点击左侧的PDF&#xff0c;点击后右侧能看到这个PDF的内容&#xff0c;每个PDF都可以点击查看&#xff0c;如果PDF内容太多&#xff0c;我们也可以通过鼠标滚动来查看。这个模板是用中继器制作的&#xff0c;所以使用也很方便…

uniapp学习(010-2 实现抖音小程序上线)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战&#xff0c;开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第113p的内容 文章目录 抖音小程序下载抖音开发者工具先去开发者工具里进行测试 抖音开放平台配置开始打包上传…

漏洞挖掘某电子商城类漏洞挖掘案例教程,手把手教你复现一个完整的漏洞挖掘全流程

前言 电子商城购物系统我们每天都能接触到&#xff0c;现在的商城系统&#xff0c;大多数已经在小程序、APP方向去开发了&#xff0c;因为灵活&#xff0c;方便管理且开发难度不高&#xff0c;当然&#xff0c;现在WEB系统还很多&#xff0c;我们本次会选几个SRC去浅挖一下那些…

C#入门013 表达式,语句详解 2

语句的定义 在计算机编程中&#xff0c;一条语句&#xff08;statement&#xff09;是命令式编程语言中表达某个要执行的动作的最小独立组成部分。用这种语言编写的程序是由一个或多个语句组成的序列构成的。语句可以包含内部组件&#xff0c;比如表达式&#xff08;expressio…

【运动的&足球】足球场景目标检测系统源码&数据集全套:改进yolo11-ASF-P2

改进yolo11-RetBlock等200全套创新点大全&#xff1a;足球场景目标检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.11.03 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或…

数据结构之复杂度

hello everybody&#xff0c;好久不见&#xff0c;由于前些日子在学习文件操作&#xff0c;预处理相关知识&#xff0c;导致我好些天没写博客了&#xff0c;所以我先从数据结构开始写吧&#xff0c;等后面熟练些了再补回来&#xff0c;欧克&#xff0c;话不多说&#xff0c;进入…

使用Jest进行JavaScript单元测试

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Jest进行JavaScript单元测试 引言 Jest 简介 安装 Jest 创建基本配置 编写测试用例 运行测试 快照测试 模拟函数 代码覆盖率…

Node.js 应用程序中的文件写入提升为 RCE

在这篇博文中,我们将强调代码安全基础的重要性。我们会展示一个技术案例:攻击者如何能够把 Node.js 应用中的文件写入漏洞转化为远程代码执行,即便目标系统的文件系统是以只读方式挂载的。这个技术通过利用暴露的管道文件描述符来获得代码执行能力,从而绕过了这类加固环境中的限…

Oracle视频基础1.4.5练习

1.4.5 看bbk的框架 ls env | grep ORA cd /u01/oradata ls ll cd bbk ll cd /u01/admin/ ll ll bbk cd cd db cd dbs ls vi initbbk.ora clear ls ll env | grep ORA执行创建数据库语句。 sqlplus /nolog conn /as sysdba create spfile from pfile ! ls ll exit startup nom…

Echats柱状图的横坐标用图片显示

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>图片作为横坐标示例 - ECharts</title><!-…

vscode php Launch built-in server and debug, PHP内置服务xdebug调试,自定义启动参数配置使用示例

在vscode中&#xff0c;当我们安装了插件 PHP Debug&#xff08;xdebug.php-debug&#xff09;或者 xdebug.php-pack 后 我们通过内置默认的 php xdebug配置启动php项目后&#xff0c;默认情况下我们在vscode中设置断点是不会生效的&#xff0c;因为我们的内置php服务默认启动时…

城镇保障性住房管理:SpringBoot系统创新点

5系统详细实现 5.1 用户信息管理 管理员可以对用户信息进行添加&#xff0c;修改&#xff0c;删除操作。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.2 房屋类型管理 管理员可以对房屋类型信息进行添加&#xff0c;修改&#xff0c;删除操作。具体界面如图5.2所示…

积极助力信创工作,爱加密荣获麒麟系统优秀合作伙伴

近日&#xff0c;麒麟软件安全生态联盟2024年第三次工作会议顺利举行。麒麟软件安全生态联盟由工业和信息化部网络安全产业发展中心指导成立&#xff0c;旨在联合打造原创性、引领性的自主操作系统内生安全技术体系和自主创新安全生态。会上&#xff0c;麒麟软件相关领导为爱加…

用图说明 CPU、MCU、MPU、SoC 的区别

CPU CPU 负责执行构成计算机程序的指令&#xff0c;执行这些指令所指定的算术、逻辑、控制和输入/输出&#xff08;I/O&#xff09;操作。 MCU (microcontroller unit) 不同的 MCU 架构如下&#xff0c;注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…

navicat pg库安装mysql fdw 外表扩展

在Windows上手动安装mysql_fdw&#xff08;MySQL Foreign Data Wrapper&#xff09;通常涉及一系列步骤&#xff0c;包括下载源码、编译、配置和测试。以下是一个详细的指南&#xff1a; 一、下载mysql_fdw源码 访问mysql_fdw的GitHub发布页面&#xff0c;选择最新版本的源码…

LongVU :Meta AI 的解锁长视频理解模型,利用自适应时空压缩技术彻底改变视频理解方式

Meta AI在视频理解方面取得了令人瞩目的里程碑式成就&#xff0c;推出了LongVU&#xff0c;这是一种开创性的模型&#xff0c;能够理解以前对人工智能系统来说具有挑战性的长视频。 研究论文 "LongVU&#xff1a;用于长视频语言理解的时空自适应压缩 "提出了一种革命…

Oracle OCP认证考试考点详解082系列09

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 41. 第41题&#xff1a; 题目 41.Examine the description of the EMPLOYEES table NLS_DATE_FORMAT is set to DD-MON-YY Which query…

【NOIP提高组】引水入城

【NOIP提高组】引水入城 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 在一个遥远的国度&#xff0c;一侧是风景秀美的湖泊&#xff0c;另一侧则是漫无边际的沙漠。该国的行政 区划十分特殊&#xff0c;刚好构成一个N行M列的矩形&#xff…

apache poi 实现下拉框联动校验

apache poi 提供了 DataValidation​ 接口 让我们可以轻松实现 Excel 下拉框数据局校验。但是下拉框联动校验是无法直接通过 DataValidation ​实现&#xff0c;所以我们可以通过其他方式间接实现。 ‍ 步骤如下&#xff1a; 创建一个隐藏 sheet private static void create…