网站首页 > 技术文章 正文
在不同操作系统之间传输字符串数据时,经常碰到因字符串的格式编码不同造成显示乱码的现象,这是由于不同操作系统使用的编码格式不一致带来的问题。本实例主要就Qt应用中经常碰到的字符串转换成Unicode、Utf8和字符内码3种编码格式的问题展开分析,如下图所示。
在实例中,用户在源字符串的编辑框中输入需要转换的字符串,可以是字符或汉字,单击“转换”按钮后,程序自动将该字符串转换成Unicode、Utf8和字符内码3种编码格式的二进制显示,即在内存中的实际存储方式,并显示不同编码格式占用的字节长度。
几种编码格式
在分析实例之前,首先对几种编码格式作一些介绍,方便大家理解。
Unicode是统一表示各种语言字符的编码标准,支持跨平台、跨程序、跨语言。它将世界上所有的字符都映射成一个数字,如“汉”为0x6C49, Unicode是一种2字节编码, 由两个字节的大小存储一个字符。
Unicode规范中推荐使用的标记字节顺序的方法是BOM (Byte Order Mark),根据内存中存放的字节顺序分为Little-Endian和Big-Endian, Little-Endian采用高值存放在高地址字节,低值存放在低地址字节的方式;Big-Endian采用高值存放在低地址字节,低值存放在高地址字节的方式。不同的体系结构采用的字节存放顺序是不一样的,如x86中通常以Little-Endian方式存放,而PowerPC中通常以Big-Endian存放。
通常来讲,Unicode指的是Little-Endian,如“汉”的Unicode值为0x6C49,实际在内存中,6C放在高地址字节,49放在低地址字节,即49 6C。对于BigEndian Unicode,“汉”在内存中,49放在高地址字节,6C放在低地址字节,即6C 49。
UTF-8是UTF (UCS Transformation Format)规范规定的一种Unicode编码表示方式,另外还有UTF-16等。UTF-8是以8位为单元对Unicode进行编码,兼容ASCII字符;UTF-16是以16位对Unicode进行编码,与ASCII字符不兼容,对于小于0x10000的Unicode, UTF-16编码就等于Unicode编码所对应16位无符号整数。UTF-8是以字节流的方式表示,没有字节顺序的问题。UTF-8与Unicode编码之间的转换规则如下:
例如,“汉”字的Unicode为0x6C49,位于0x0800?OxFFFF之间,对应的UTF-8字节流为1110xxxx 10xxxxxx 10xxxxxx,UTF-8编码采用三字节表示,0x6C49的二进制为0x0110110001001001,将这16位分别替换上面的X,可以得到11100110 10110001 10001001,即E6B189,这就是中文“汉”字的UTF-8编码。
字符内码指的是用来代表字符的内码,包括单字节内码和双字节编码,单字节内码就是ASCII码,可以表示256个字符编码;双字节内码就是ANSI,可以表示65000个字符编码。对于简体中文编码GB2312,实际上对应的是ANSI的一个代码页936。ANSI有很多代码页,使用不同代码页的内码无法在其他代码页正常显示,如繁体中文、日文都对应ANSI的一个代码页,这些内码无法在简体中文GB2312的平台上正常显示。对于GB2312来说,用一字节表示一个字符,每一个汉字由两个字符构成,因此每一个汉字占两个字节。
实例代码
转换函数的代码如下:
void Widget::on_btnConvert_clicked()
{
ui->edtUnicode->clear(); // 首先清空各控件的内容
ui->edtBigEndian->clear();
ui->edtUtf8->clear();
ui->edtLocal->clear();
QString source=ui->edtSrc->text(); // 获得用户输入的源字符串
const QChar *u=source.unicode(); // (a)
// 获得Unicode编码
ui->edtUnicodeLen->setText(QString::number(source.length()*2)); // (b)
for(int i=0;i<source.length();i++) {
const ushort unicode=u[i].unicode(); // (c)
ui->edtUnicode->insert(QString::number(unicode%256,16)+" "); // (d)
ui->edtUnicode->insert(QString::number(unicode/256,16)+" ");
}
// 获得 Big-Endian Unicode 编码
ui->edtBigEndianLen->setText(QString::number(source.length()*2));
for(int i=0;i<source.length();i++) {
const ushort unicode=u[i].unicode();
ui->edtBigEndian->insert(QString::number(unicode/256,16)+" "); // (e)
ui->edtBigEndian->insert(QString::number(unicode%256,16)+" ");
}
// Utf8
QByteArray b=source.toUtf8(); // (f)
ui->edtUtf8Len->setText(QString::number(b.length())); // (g)
for (int i=0;i<b.length();i++) {
const unsigned char a=b[i];
ui->edtUtf8->insert(QString::number(a,16)+" "); // (h)
}
// Local
QByteArray bl=source.toLocal8Bit(); // (i)
ui->edtLocalLen->setText(QString::number(bl.length()));
for (int i=0;i<bl.length();i++) {
const unsigned char a=bl[i];
ui->edtLocal->insert(QString::number(a,16)+" ");
}
}
其中:
- (a):获得QString对象的Unicode编码,这是一个QChar*对象,QChar提供了一种16位表示Unicode的方式,使用两个字节表示一个字符。
- (b):获得源字符串的Unicode编码的长度,由于Unicode采用两个字节来表示一个字符,因此,这里通过源字符串长度的两倍得到Unicode的长度。
- (c):通过QChar的unicode()方法获得每一个字符的Unicode编码值,这是一个ushort类型的值,占两个字节。
- (d):分别获得ushort值的低值和髙值字节,由于Unicode采用的是Little-Endian方式,因此,低值字节存放在低地址字节上,高值字节存放在高地址字节上。
- (e):分别获得ushort值的高值和低值字节,由于这里采用的是Big-Endian方式,因此,髙值字节存放在低地址字节上,低值字节存放在高地址字节上。
- (f):通过QString的toUtf8()方法得到源字符串的UTF-8编码序列,这是一个QByteArray对象,QByteArray提供了一种字节流的表示方式。
- (g):获得该字节流的长度信息,这就是源字符串的UTF-8编码所占用的字节长度。
- (h):分别对字节流的每一个字节按十六进制的形式显示,UTF-8没有字节顺序的问题,因此QByteArray中存放的字节流顺序就是内存中存放的字节顺序。
- (i):获得源字符串的字符内码编码序列,这也是一个QByteArray对象,通过QString的toLocal8Bit()可以获得本地8位字符内码编码的字节流。
——————————————————
对于本文实例完整代码有需要的朋友,可关注并在评论区留言!
猜你喜欢
- 2024-10-09 C++Qt的字符编码(qt中文编码)
- 2024-10-09 从零开始学Qt(29):字符串QString类的常用功能
- 2024-10-09 QT(1)- QString(qt qstring c_str)
- 2024-10-09 C++跨平台库QT学习5 字符串处理类QString的使用
- 2024-10-09 QString的解析与常用功能(qstring::number 保留2位小数)
- 2024-10-09 【Qt5】QString的成员函数arg(qt arg函数)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- js判断是否空对象 (63)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- phprequire_once (61)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)