【问题】Qt c++ 因编码问题解析json失败
问题
项目上遇到一个很离谱的问题,json如下:
{
"Place": "北滘"
}
这是一个正常的json,他的编码是GB2312,可是我的代码在解析json时报错,代码如下:
// 判断是否为GB2312编码
bool isGb2312(const QByteArray &data) {
QTextCodec *codec = QTextCodec::codecForName("GB2312");
if (!codec)
return false;
QString decodedString = codec->toUnicode(data);
QByteArray encodedData = codec->fromUnicode(decodedString);
return data == encodedData;
}
QJsonParseError parseError;
bool ParseJsonVerson(QByteArray pBody, QString &strErrMsg){
if(isGb2312(fileJsonData)){
QTextCodec *codec = QTextCodec::codecForName("GB2312");
if (codec)
pBody = codec->toUnicode(pBody).toUtf8();
}
QJsonDocument jsonDoc = QJsonDocument::fromJson(pBody, &parseError);
if (jsonDoc.isNull()) {
bRet = false;
strErrMsg = "解析失败,不是完整的json11!";
qWarning() << "Failed to create JSON document:" << parseError.errorString();
return bRet;
}
//json处理....
}
这里运行时,jsonDoc.isNull()=true
!
一脸懵逼,没办法单步进去查看,发现它判断的json编码不是"GB2312"
!!!!
继续查,发现我把“滘”字删掉就正常了!???
直接定位“滘”字细节如下:
单纯的“滘” 他的16进制数据是 0x9C 0xF2
调用bool isGb2312(const QByteArray &data)
接口:
这里明显发现不对了,转换回来失败了!
我们使用“好”字再来测试:
QString decodedString = codec->toUnicode(data);
做了什么?
QTextCodec::toUnicode
QTextCodec::toUnicode 方法的实现涉及将字节数组(QByteArray)转换为 QString。在 Qt 中,QTextCodec 是一个抽象类,负责处理不同字符编码之间的转换。具体到 GB2312 编码,toUnicode 方法的实现过程大致如下:
-
字节解析:首先,toUnicode 方法会读取输入的字节数组,并根据 GB2312 编码的规则解析字节。GB2312 是一个双字节编码,字符的表示通常由两个字节组成。
-
字符映射:对于每一对字节,toUnicode 会查找 GB2312 字符集中的对应字符。如果字节对在 GB2312 字符集中存在,则返回相应的 Unicode 字符。
-
错误处理:如果输入的字节数组包含无效的字节序列(例如,单独的字节或不在 GB2312 字符集中的字节对),toUnicode 方法会返回一个替代字符(通常是 U+FFFD,即 “�”),表示无法识别的字符。这就是你在调用 toUnicode 时得到 0xFFFD 的原因。
返回结果:最后,toUnicode 方法将所有有效的字符组合成一个 QString 并返回。
问题定位了,QTextCodec::toUnicode 没能成功将“滘”字转换成Unicode。查询了一下GB2312字符集中没有“滘”这个字!!!
0x9C 0xF2 编码表示的是汉字“滘”,属于GBK编码!!!
解决办法:
// 检测文件编码
QString detectEncoding(QByteArray data) {
if (isUtf8(data)) {
return "UTF-8";
} else if (isGb2312(data)) {
return "GB2312";
} else if (isGbkEncoded(data)){
return "GBK";
}
else {
return "Unknown";
}
}
bool ParseJsonVerson(QByteArray pBody, QString &strErrMsg){
if(strCode=="Unknown"){
strErrMsg = "解析失败,未知编码!";
qWarning() << "Failed to create JSON document:" << parseError.errorString();
return bRet;
}
else if(strCode=="GB2312"){
QTextCodec *codec = QTextCodec::codecForName("GB2312");
if (codec) {
pBody = codec->toUnicode(pBody).toUtf8();
}
}
else if(strCode=="GBK"){
QTextCodec *codec = QTextCodec::codecForName("GBK");
if (codec) {
pBody = codec->toUnicode(pBody).toUtf8();
}
}
QJsonDocument jsonDoc = QJsonDocument::fromJson(pBody, &parseError);
if (jsonDoc.isNull()) {
bRet = false;
strErrMsg = "解析失败,不是完整的json11!";
qWarning() << "Failed to create JSON document:" << parseError.errorString();
return bRet;
}
//json处理....
}