前言
有时候程序显示的中文是乱码,这就需要对编码有一定的了解才能避免中文乱码的问题。
字符编码
任何字符在计算机内部都是用数字表示的,即字符编码
不同国家和地区都为自己的语言定义了不同的编码标准:
- 英语国家:基本 ASCII,用 1 个字节编码,数字 0~127 代表 128 个字符,包括英语中的大小写字母、数字 0~9、标点符号、换行符、制表符、退格符等
- 欧洲国家:扩展 ASCII(Latin1),也是用 1 个字节编码,它用 128~255 表示拉丁字母表中特殊语言字符的编码
- 中国大陆:GBK,21003 个字符
- 港台地区:BIG5,13060 个字符
ASCII 和 Latin1 都是使用 1 个字节编码,最多只有 256 个字符,无法表示汉字、日语等其他语言里的字符,虽然其他国家各自制定了满足本国需求的字符编码,但各国之间编码不统一,带来了许多麻烦,因此又出现了 Unicode 编码。
统一编码
国际标准化组织制定的 ISO/IEC 10646 标准是一种可以支持世界上所有语言文字的字符编码标准,称为 Unicode
根据字长的不同,Unicode 又被分为两个字符集:UCS-2 和 UCS-4
UCS 转换格式(UCS Transformation Format,UTF)
无论是 UCS-2 还是 UCS-4,作为 Unicode 字符集,它们都只是规定了如何对一个字符编码,但并没有规定如何传输、保存这个编码,即在程序中如何表示这个编码,而 UTF 所要解决的就是这个问题。
根据转换算法的不同 Unicode 的存储方式可以被分为:UTF-8、UTF-16、UTF-32
UTF-8 表示最少使用 8 位(即 1 个字节)来代表 1 个字符。当需要使用更多的字节表示一个字符时,UTF-8 会在第一个字节的高位标记这个字符需要使用的总字节数。因此,UTF-8 编码中的一个字符可能会使用 1~4 个字节。
同理,UTF-16 表示最少使用 2 个字节编码。
Qt 内部编码
Qt Creator 存储的 C++ 语言头文件和源程序文件都是默认使用 UTF-8 编码
但是,QString、QChar、QTextStream 类使用的是 UTF-16 编码
在 QString Class 中的描述中已经给出:
The QString class provides a Unicode character string.
QString str{"你好"};
qDebug("str = %s", str.data()); // str = `O}Y
qDebug("str = %s", str.toStdString().c_str()); // str = 你好
qDebug("str = %s", str.toLocal8Bit().data()); // str = ????
qDebug("str = %s", str.toUtf8().data()); // str = 你好
qDebug() << "QString :" << sizeof(QString); // QString : 24
qDebug() << "str :" << sizeof(str); // str : 24
qDebug() << "str[1] :" << sizeof(str[1]); // str[1] : 2
qDebug() << "char* :" << sizeof("hello"); // char* : 6
qDebug() << "std::string :" << sizeof(std::string); // std::string : 40
qDebug() << "std::string :" << sizeof(str.toStdString().c_str()[1]); // std::string : 1
qDebug() << "int :" << sizeof(int); // int : 4
外部编码
程序源代码中使用的字面值形式的字符和字符串、用户通过程序界面输入的字符和字符串,以及程序通过文件、网络、进程间通信或其他媒介读取的字符和字符串,受系统环境等因素的影响,通常会是各种各样的编码格式,一般将其统称为外部编码
编码转换
默认情况下,Qt 5以后的版本都能正确理解 UTF-8 格式编码,并将其自动转换为内部的 Unicode 编码。
如果使用 UTF-8 的中文字符串总是能够正确显示,但是如果使用其他格式的外部编码,比如 Windows 中常用的 GBK 编码,将会出现乱码现象。
解决办法:通过 QTextCodec 实现编码转换
QTextCodec *codec = QTextCodec::codecForName("GBK");
QString string = codec->toUnicode("将GBK编码的中文字符串改为Unicode编码")
在 Qt 6 往后的版本中,QTextCodec 已被去除,需要安装扩展模块 Qt 5 Compatibility Module
详情见:QT6中QTextcodec头文件找不到 - CSDN