Qt中的字符编码转换:UTF8、Unicode、GBK、ASCII、16进制字符、16进制数值

前言

字符编码方式多种多样,往往不同的应用、不同的设备、不同的系统上使用的字符编码不同,因此想要设计鲁棒性强的软件,就必须掌握对字符编码的转化机制和具体实现,特别是在Qt这样的跨平台框架上。特别地,本文就Qt串口通信助手中需要的字符编码转换进行探讨。

简述

ASCII

ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符。

GBK

GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification) ,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订,国家技术监督局标准化司、电子工业部科技与质量监督司1995年12月15日联合以技监标函1995 229号文件的形式,将它确定为技术规范指导性文件。这一版的GBK规范为1.0版。

Unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。

UTF-8

UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。

应用场景

  • ASCII编码只使用一个字节表示字符,占用空间小,因此在嵌入式领域非常常见,常用于数据传输。
  • GBK编码常见于Window平台,使用双字节编码,由于是国家标准,主要用于中文编码,因此通用性有一定局限性,
  • Unicode是计算机科学领域里的一项业界标准,通用性较强,但是需要的存储空间更多。
  • UTF-8是针对Unicode编码过大的一种优化,采用变长度字节(1-6个直接)存储,且兼容ASCII,逐渐变得流行。
  • Unicode与UTF-8的区别在于,Unicode是字符集,而UTF-8是Unicode的编码方式。
  • 需要通用性采用UTF-8,需要更多存储空间采用GBK。

开发环境

  • Qt Creator 4.10.1
  • Qt 5.13.2(默认为Unicode编码)
  • MinGw 32-bit编译器
  • Win10系统(默认为GBK编码)

编码转换

16进制数值转换为16进制字符

  • 转换机制:将串口接受到的数据按比特进行字符化
QString CharEncodingTrans::QByteArray_to_HexQString(const QByteArray &data)
{
    char tmp_byte;
    QString tmp_qstr;
    foreach(char byte, data)
    {
        // 高字节
        tmp_byte = (byte & 0xF0)>>4;
        tmp_qstr += (tmp_byte < 10) ? tmp_byte+'0' : tmp_byte+'A'-10;

        // 低字节
        tmp_byte = byte&0x0F;
        tmp_qstr += (tmp_byte < 10) ? tmp_byte+'0' : tmp_byte+'A'-10;
        tmp_qstr += ' ';
    }
    return tmp_qstr;
}

16进制数值转化为字符串

  • 笔者的开发环境为win10,所以QTextCodec::codecForName("System")采用的编码为GBK编码,因此tc->toUnicode()在这里的意义是从GBK编码转换为Unicode,进而在Qt的textEdit上显示。
QTextCodec* tc = QTextCodec::codecForName("System");
tmp_qstr = tc->toUnicode(data)

16进制字符串转换为Unicode字符串

  • 转换机制:仅16进制字符串先转换为16进制数值,再通过16进制数值转换为字符串。
  • 使用Qt中QByteArray的append函数,ascii_data.append(str);将16进制字符串储存在QByteArray中,再通过QByteArray::fromHex()静态函数将QByteArray的16进制字符串转换成对应的ascii码字符串。
  • 最后通过QTextCodec将字符串编码转化为Qt默认的Unicode编码
QString HexQString_to_QString(const QString &text)
{
    QTextCodec *tc = QTextCodec::codecForName("System");
    // 将Hex字符串转换为Ascii字符串
    QString temp;
    QByteArray ascii_data;
    QStringList temp_list = text.split(' ', QString::SkipEmptyParts);
    foreach(QString str, temp_list)
    {
        ascii_data.append(str);
    }
    // 将ascii_data中的16进制数据转化为对应的字符串,比如\x31转换为"1"
    temp = tc->toUnicode(QByteArray::fromHex(ascii_data));
    return temp;
}

Unicode字符串转化为16进制字符串

  • 转换机制:将16进制字符串先转换为16进制数值,这里通过使用QByteArray的append函数。但是这里需要注意的是,由于是开发在windows上的程序,所以编码采用GBK编码,所以要讲中文对应的16进制编码换成GBK编码,然后再转化为字符串。
  • 同时由于QByteArray中存储的16进制数,并不是以数值存在的,而是以字符串形式存在的,所以要使用toHex()函数,将“\x31”转换0x31。
QString CharEncodingTrans::QString_to_HexQString(const QString &text)
{
	QTextCodec *gbk = QTextCodec::codecForName("System");
    QString temp;
    QByteArray hex_data;
    foreach(QChar byte, text)
    {
        hex_data.append(gbk->fromUnicode(byte));
    }
    // 将hex_data中的16进制转化为
    temp = gbk->toUnicode(hex_data.toHex()).toUpper();
    // 在字符串中每两个字符添加一个空格,为了防止叠加效应,选择从后面开始添加
    for(int i = temp.length(); i > 0; i -=2)
        temp.insert(i, ' ');
    return temp;
}

总结

  1. Qt中的QTextCodec提供强大的字符集转换功能
  2. QByteArray功能强大,可以作为很多字符转换操作的载体
    • QByteArray::fromHex将存储在QByteArray中的16进制字符串转换为对应的ascii字符
    • QByteArray::toHex将16进制字符串转化为对应的数值
  3. Qt默认使用Unicode作为字符编码,window默认使用GBK作为字符编码

参考资料

  1. https://baike.baidu.com/item/ASCII/309296?fr=aladdin
  2. https://baike.baidu.com/item/GBK%E5%AD%97%E5%BA%93/3910360?fromtitle=GBK&fromid=481954&fr=aladdin
  3. https://baike.baidu.com/item/Unicode/750500?fr=aladdin
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章