文章目录
前言
字符编码方式多种多样,往往不同的应用、不同的设备、不同的系统上使用的字符编码不同,因此想要设计鲁棒性强的软件,就必须掌握对字符编码的转化机制和具体实现,特别是在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;
}
总结
- Qt中的QTextCodec提供强大的字符集转换功能
- QByteArray功能强大,可以作为很多字符转换操作的载体
- QByteArray::fromHex将存储在QByteArray中的16进制字符串转换为对应的ascii字符
- QByteArray::toHex将16进制字符串转化为对应的数值
- Qt默认使用Unicode作为字符编码,window默认使用GBK作为字符编码
参考资料
- https://baike.baidu.com/item/ASCII/309296?fr=aladdin
- https://baike.baidu.com/item/GBK%E5%AD%97%E5%BA%93/3910360?fromtitle=GBK&fromid=481954&fr=aladdin
- https://baike.baidu.com/item/Unicode/750500?fr=aladdin