一、简介
在Qt开发过程中,从linux获取的中文字符串很容易出现乱码,linux创建的文件取决于不同的工具,有可能是GBK格式,有可能是UTF-8。所以需要一个通用的方式把中文转成正常的字符串显示出来。
Qt处理中文的方式:
| 编码类型 | 适用场景 | Qt 中对应的解析方式 |
|---|---|---|
| DOS 中文 | DOS 环境下的文本 / 数据 | GBK/GB2312(属于 Windows Local8Bit) |
| Windows 本地编码 | 系统默认 ANSI 编码 | QString::fromLocal8Bit() |
| Qt 内部编码 | 字符串存储(无乱码) | UTF-16(无需关心,Qt 自动处理) |
| UTF-8(通用) | 跨平台推荐 | QString::fromUtf8() |
二、详解
1、 确认源数据的真实编码
(1)打印源字符串的十六进制数,对比编码表判断真实编码
#include <QDebug>
#include <QTextCodec>
// 打印字节数组的十六进制(用于判断编码)
void printHex(const QByteArray &data) {
QString hexStr;
for (char c : data) {
hexStr += QString("%1 ").arg(static_cast<unsigned char>(c), 2, 16, QChar('0'));
}
qDebug() << "源数据十六进制:" << hexStr.trimmed();
}
| 中文 | GBK (CP936) 十六进制 | UTF-8 十六进制 | DOS CP850(无中文,仅西文) |
|---|---|---|---|
| 你好 | B0 A1 C4 E3 | E4 BD A0 E5 A5 BD | 无对应(显示乱码符号) |
| 张三 | D5 C5 C8 FD | E5 BC A0 E4 B8 89 | 无对应 |
2、 复用的 Qt 通用编码转换代码
调用autoConvertToWindows即可获取转换后的中文
bool hasValidChinese(const QString &text)
{
// 匹配中文Unicode区间:[\u4e00-\u9fa5]
return text.contains(QRegExp("[\\u4e00-\\u9fa5]"));
}
bool isCompleteGbk(const QByteArray &data)
{
int len = data.length();
if (len % 2 != 0) { // GBK中文必为2字节,奇数长度=截断
qWarning() << "GBK字节流不完整:长度为奇数(" << len << "),可能截断";
return false;
}
// 校验每个GBK字符的高位字节范围(GBK高位:0x81-0xFE)
for (int i = 0; i < len; i += 2) {
unsigned char high = static_cast<unsigned char>(data[i]);
if ((high<0x81) || (high>0xFE)) {
return false;
}
}
return true;
}
QString autoConvertToWindows(const QByteArray &dosData)
{
// 1. 先尝试GBK/CP936(最常见的DOS中文编码)
QTextCodec *gbkCodec = QTextCodec::codecForName("CP936");
if (!gbkCodec) {
gbkCodec = QTextCodec::codecForLocale();
}
QString text = gbkCodec->toUnicode(dosData);
// 2. 验证转换结果是否为有效中文(避免乱码)
if (hasValidChinese(text) && isCompleteGbk(dosData)) { // 包含中文字符,转换成功
return text;
}
// 3. 尝试UTF-8(误判为DOS编码的情况)
text = QString::fromUtf8(dosData);
if (hasValidChinese(text)) {
return text;
}
// 4. 尝试DOS CP850转GBK
QTextCodec *cp850Codec = QTextCodec::codecForName("CP850");
if (cp850Codec) {
QString unicodeText = cp850Codec->toUnicode(dosData);
text = QString::fromLocal8Bit(unicodeText.toLocal8Bit());
if (hasValidChinese(text)) {
return text;
}
}
text = QString::fromLocal8Bit(dosData);
return text;
}
四、总结
上述代码经过不断添加格式解析,覆盖 DOS(CP850/CP437)、Windows 本地编码(GBK/CP936)、UTF-8 所有场景。自动识别源编码并转换为 Windows 可正常显示的 Qt 字符串,解决Qt中各类中文乱码问题。