Qt编写区位码gb2312、机内码、国标码————附带详细介绍和编码实现

文章目录

  • [0 背景](#0 背景)
  • [1 了解编码](#1 了解编码)
    • [1.1 ASCII码](#1.1 ASCII码)
    • [1.2 机内码、国标码、区位码](#1.2 机内码、国标码、区位码)
      • [1.2.1 区位码](#1.2.1 区位码)
      • [1.2.2 国标码(GB 2312-80)](#1.2.2 国标码(GB 2312-80))
      • [1.2.3 汉字机内码(GB 2312)](#1.2.3 汉字机内码(GB 2312))
  • [1.3 GBK和GB2312的区别](#1.3 GBK和GB2312的区别)
  • [2 编码实现](#2 编码实现)
    • [2.1 QString数据转QByteArray类型](#2.1 QString数据转QByteArray类型)
      • [2.1.1 使用QTextCodec](#2.1.1 使用QTextCodec)
      • [2.1.2 使用toLocal8Bit(推荐)](#2.1.2 使用toLocal8Bit(推荐))
    • [2.2 QByteArray数据转QString类型](#2.2 QByteArray数据转QString类型)
    • [2.3 测试区位码gb2312](#2.3 测试区位码gb2312)
      • [2.3.1 测试代码1(推荐)](#2.3.1 测试代码1(推荐))
      • [2.3.2 测试代码2](#2.3.2 测试代码2)
  • 参考

0 背景

因为需要对发送的汉字数据进行区位码编码,于是查询了如何进行编码。下文是查询笔记和实现总结。

1 了解编码

编码前,首先要了解四个码:ASCII码、机内码、国标码、区位码。

1.1 ASCII码

键盘上数字、字母和符号的单个为字符,组合起来成为字符串。

键盘上所能表示的字符有128个,刚好是2^7^,在7位的最前面补一个0,变成8位(bit),即一个字节(Byte)。每个字符都对应一个8位的二进制编码。

上表为10进制表示的ASCII码表,例如字母A对应的10进制数为65,表示的16进制为41H,即二进制编码:0100,0001。

ASCII码中字符被分成三类:可印刷字符、控制字符、通信字符

1,可印刷字符:32~126都是可印刷字符。可以打印出来给人看的。

2,控制字符:127是控制字符,DEL就是键盘上的delete,用于删除。

3,通信字符:0~32,比如6,ACK,在两个电脑通信时,会一方接到另一方传来的数据时,就会回一个ACK包。

1.2 机内码、国标码、区位码

机内码、国标码、区位码的三者转换关系为:

读取数据编码时:

机内码--->国标码---->区位码

1,把数据按字符串读取,就可以得到机内码;

2,机内码减去8080H(将最高位变为0),就是国标码;

3,国标码再减去32(2020H),就是区位码;

接收数据解码时:

区位码---->国标码--->机内码

1,把区位码加上2020H(区分ASCII码中的通信字符),得到国标码(GB2312-80);

2,把国标码加上8080H(区分ASCII码中的全部字符),得到 汉字机内码(GB2312)。

1.2.1 区位码

因为ASCII码只能表示英文字母,想表示中文,就需要额外的编码。这里使用的就是区位码(区域位置码)。

区位码中,汉字被分成了94个区域,每个区域有94个位置。就像是坐标一样,区是横坐标,位是纵坐标。

如下面区位码表中,的区位码为1601H,即16H是区,01H是位。

关于GB2312字符集的编集如下:

1,01~09区(682个):特殊符号、数字、英文字符、制表符等,包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等在内的682个全角字符;

2,10~15区:空区,留待扩展;

3,16~55区(3755个):常用汉字(也称一级汉字),按拼音排序;

4,56~87区(3008个):非常用汉字(也称二级汉字),按部首/笔画排序;

5,88~94区:空区,留待扩展。

1.2.2 国标码(GB 2312-80)

在网络传输过程中:A要给B传输一个数据,如果A传去的数据是用GB2312-80编的,而B读取地方式是用ASCII方式的,GB 2312-80将区位码传过去,当B收到时会先读到区码,因为区码和位码的范围用十进制表示都是0~93,如果此时的区码的十进制是6,那么ASCII对应的6则是ACK,会发现ACK是回包的指示。那么就会出现问题。

为了解决这一问题,将区位码的区码和位码都+32,区码和位码的范围就变成了32-125,而ASCII的通信字符是0到32,就避开了与ASCII中通信字符与控制字符的相同的情况,提高了ASCII和区位码的兼容性。

而这种32~125的区位码就是:国标码(GB2312 -80)

但是国标码是用十六进制表示的,实际上是在区位码的区码和位码分别加上20H(十进制:32),也就是加上2020H,最后得到了GB 2312-80

1.2.3 汉字机内码(GB 2312)

国标码是为了防止与ASCII的控制字符和通信字符冲突,但是还是会和打印字符发送冲突,因此为了彻底让国标码和ASCII兼容。就再GB 2312-80(国标码)的基础上分别在加上8080H,也就是在区码和位码上再加上128(80H)。最后得到了:汉字机内码,GB 2312就是汉字机内码。

由于ASCII的范围是再0-127,而GB 2312在(128+32=160)160~253(93+160),因此GB2312与ASCII就不会发生冲突了,使得中国汉字与外国英文兼容了。

最后在计算机内部,使用的就是汉字机内码(GB 2312)。

1.3 GBK和GB2312的区别

收录不同:GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;GBK共收入21886个汉字和图形符号。

表示不同:GB2312对任意一个图形字符都采用两个字节表示,并对所收汉字进行了"分区"处理,每区含有94个汉字/符号,分别对应第一字节和第二字节。GBK是采用单双字节变长编码,英文使用单字节编码,完全兼容ASCII字符编码,中文部分采用双字节编码。

GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大。

2 编码实现

编码后,使用如下工具进行查询和比对:

1,汉字区位码查询网站;

2,在线转换查询网站

3,在线查询软件

2.1 QString数据转QByteArray类型

2.1.1 使用QTextCodec

该类的官方使用文档

注意:QTextcodec在QT6中已经被弃用,取而代之的是QTextCodec(注意大小写)。

头文件:

cpp 复制代码
#include <QTextCodec>
#include <qDebug>
#include <QByteArray>
cpp 复制代码
    QByteArray content = "啊阿埃挨";
    QByteArray resData = QTextCodec::codecForName("GB2312")->fromUnicode(content);
    qDebug()<<resData.toHex().toUpper();

输出:

cpp 复制代码
B0A1B0A2B0A3B0A4

2.1.2 使用toLocal8Bit(推荐)

cpp 复制代码
     QString str("啊");
     QByteArray data = str.toLocal8Bit();//转为本地8bit编码格式,对于windows系统,本地编码格式为GBK,linux系统为UTF-8。
     qDebug()<<"resData:"<<data.toHex().toUpper();

输出:

cpp 复制代码
B0A1

2.2 QByteArray数据转QString类型

cpp 复制代码
QByteArray content = "啊阿埃挨";
QByteArray resData = QTextCodec::codecForName("GB2312")->fromUnicode(content);
QString strUnicode= QTextCodec::codecForName("GB2312")->toUnicode(resData.data());
qDebug()<<strUnicode;

2.3 测试区位码gb2312

2.3.1 测试代码1(推荐)

cpp 复制代码
     QString str("啊");
     QByteArray data = str.toLocal8Bit();//获取机内码 :转为本地8bit编码格式,对于windows系统,本地编码格式为GBK,linux系统为UTF-8。

    QByteArray resData;
    char first = data.data()[0] - 0xa0;
    char second  = data.data()[1] - 0xa0;
    resData += first;
    resData += second;

    QString hexStringHigh = resData.mid(0,1).toHex();
    QString hexStringLow = resData.mid(1,1).toHex();
    bool ok;
    uint decimalHigh = hexStringHigh.toUInt(&ok, 16);
    uint decimalLow = hexStringLow.toUInt(&ok, 16);

    qDebug()<<"汉字机内码:"<<data.toHex().toUpper();
    qDebug()<<"16进制的区位码gb2312:"<<resData.toHex().toUpper();
    qDebug()<<"10进制的区位码gb2312:"<<decimalHigh<<decimalLow;

输出:

cpp 复制代码
汉字机内码: "B0A1"
16进制的区位码gb2312: "1001"
10进制的区位码gb2312: 16 1

2.3.2 测试代码2

cpp 复制代码
    QString text_str("啊");
    const char *hanzi=qPrintable(text_str);
    QByteArray ba(hanzi);
    char *data = ba.data();

    char s[3];
    s[0]='0';
    s[1]='0';
    s[2]='0';

    sprintf(s, "%x", data[0]);
    QString qstr1 = QString::fromStdString(s);
    sprintf(s, "%x", data[1]);
    QString qstr2 = QString::fromStdString(s);

    QString s1=qstr1.right(2);
    QString s2=qstr2.right(2);

    bool ok;
    int quwei=(s1.toUpper()+s2.toUpper()).toInt(&ok,16)-0xA0A0;
    QString qstr3=QString::number(quwei,16);

    qDebug()<<"汉字内码高位:"<<s1;
    qDebug()<<"汉字内码低位:"<<s2;
    qDebug()<<"16进制区位码:"<<qstr3;

参考

srhqwe:编码格式说明

涛··:Qt之GB2312\GBK字符与QString转换

wkm956:Qt获取汉字区位码

丁老师的技术随笔:Qt 汉字内码及区位码 提取

相关推荐
糯诺诺米团9 小时前
Qt|QWidget窗口支持旋转
开发语言·qt
SunkingYang10 小时前
qt中如何判断字符串是否为数字,整数,浮点数?
qt·方法·数字·整数·浮点数·判断字符串
꧁坚持很酷꧂10 小时前
Qt天气预报系统设计界面布局第四部分右边
开发语言·qt
-凌凌漆-13 小时前
【Qt】QLabel同时显示图片和文字,图片作为背景,文字显示在上层
qt
Chris·Bosh13 小时前
QT:控件属性及常用控件(1)------核心控件及属性
开发语言·c++·qt
咬光空气1 天前
Qt 5.14.2 学习记录 —— 사 信号与槽机制(1)
开发语言·qt·学习
吃不饱的得可可1 天前
【Qt】主窗口
开发语言·qt
You can do more2 天前
Qt qtcreator配置cmake
qt
yuanbenshidiaos2 天前
QT-------绘图
开发语言·数据库·qt
繁星蓝雨2 天前
Qt实现使用TCP与RS485串口设备通信————附带详细实践方法
qt·modbus·modbus tcp·rs485·modbus rtu