QT中出現的中文亂碼問題及其解決方案

基本概念

字庫表:是一個系統支持的文字,符號,數字的集合。
編碼字符集(字符集):計算機是以二進制的形式存儲字符的,每個字符對應的二進制編碼不同,而編碼字符集就是所有編碼與字符的映射集合。例如:在ASCII碼的編碼字符集中,字母A的編碼是65,65的二進制就是01000001。
字符編碼:不同字符的編碼不同,其二進制的位數也不同。爲了達到節省空間,解析方便等目的,出現了多種存儲字符編碼的方式,每種方式對應一套算法,這套算法也稱字符編碼。例如Unicode字符集,utf-8,utf-16字符編碼。
源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存時採用哪種字符編碼。
執行字符集:可執行應用程序內使用何種字符編碼。編譯器會將源碼字符集轉換爲執行字符集。

情況一

軟件平臺:Windows 10,Qt Cretor 4.7.2,
問題描述:運行一個基於QT框架的的GUI應用程序時,界面上的PlainTextEdit組件無法正常顯示中文形式的QString字符串,此外,在控制檯中,也無法正常輸出中文形式的QString字符串,即都出現了中文亂碼。如下所示:

void Dialog::on_pushButton_clicked()
{//QHostInfo獲取主機信息
  QString hostName=QHostInfo::localHostName(); //本地主機名
  ui->plainTextEdit->appendPlainText("本機主機名:"+hostName+"\n");
  QHostInfo hostInfo=QHostInfo::fromName(hostName); //本機IP地址

  QList<QHostAddress> addList=hostInfo.addresses(); // IP地址列表
  if(!addList.isEmpty())
    for(int i=0;i<addList.count();i++)
    {
      QHostAddress aHost=addList.at(i); //每一項是QHostAddress
      bool show=ui->checkBox->isChecked(); //只顯示IPv4
      if(show)
        show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //IPv4協議
      else
        show=true;
      if(show)
      {
        ui->plainTextEdit->appendPlainText("協議:"+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText("本機IP地址:"+aHost.toString());
        ui->plainTextEdit->appendPlainText("");
      }
    }

}

在這裏插入圖片描述

QString hello="中文";
  qDebug()<<hello;

在這裏插入圖片描述

QString顯示中文亂碼的原因

QString的內部採用unicode字符集,utf-16編碼。構造函數QString::QString(const char *str)默認使用fromUtf8()將str所指的執行字符集從utf-8轉碼成utf-16。由fromUtf8()可知,QString需要執行字符集編碼爲utf-8,然後以utf-8進行解碼,再編碼爲utf-16才能獲得正確的字符編碼。所以,顯示中文亂碼的原因爲:QString的轉碼方式與執行字符集不一致。(比如,源文件字符集爲本地字符集GBK編碼,QString以utf-8的方式進行解碼,會導致獲得錯誤的二進制編碼,再將錯誤二進制轉爲utf-16就會出現亂碼。)

注意:
1.當Qt 5.11.3 MinGW 32bit編譯程序的時候,會分析源代碼文件採用何種編碼,有BOM標識符則可以正確識別其編碼,若沒有BOM標識符則認爲其使用本地字符編碼local字符集。此處使用的windows 10的本地字符編碼爲GBK編碼。
2.編譯器分析出源文件字符編碼之後,會進行解碼再編碼,將源字符集轉碼成執行字符集。執行字符集一般默認爲使用本地字符編碼local字符集,也可以進行設置。

中文亂碼測試

在GUI應用程序的主函數裏創建一個QString對象hello,因爲QString構造函數內部調用了QString::fromUtf8(),所以hello和QString::fromUtf8(“中文”)的表現應該是一致的。QString::fromLocal8Bit()將執行字符集以本地編碼轉爲utf-16。如下爲具體代碼:

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Dialog w;
  w.show();

  QString hello="中文";
  qDebug()<<hello;
  qDebug()<<QString::fromUtf8("中文");
  qDebug()<<QString::fromLocal8Bit("中文");

  return a.exec();
}

例1:源文件代碼的編碼字符集爲GB2312(Simplified),程序結果如下:
在這裏插入圖片描述
結果表明,前兩種發生了亂碼,fromLocal8Bit()顯示正常。源代碼文件的源文件代碼的編碼字符集爲GB2312(Simplified),不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲操作系統的本地編碼,而源代碼文件的編碼的確與本地編碼一致,所以fromLocal8Bit顯示正常。因爲fromUtf8將執行字符集以utf-8進行解碼,顯示亂碼。

例2:源文件代碼的編碼字符集爲UTF-8,程序結果如下:
在這裏插入圖片描述結果表明,前兩種顯示正常,fromLocal8Bit()發生了亂碼。源代碼文件的源文件代碼的編碼字符集爲UTF-8,不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲本地編碼,執行字符集也是本地編碼,因此不會進行轉碼,但實際上執行字符集是utf-8編碼。因此fromUtf8將執行字符集以utf-8進行解碼,顯示正確;而fromLocal8Bit將執行字符集以本地編碼進行解碼,顯示亂碼。

解決方案

由於程序的源代碼文件採用的編碼方式是GB2312(Simplified),不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲操作系統的本地編碼,而源代碼文件的編碼的確與本地編碼一致,所以fromLocal8Bit顯示正常。所以解決中文亂碼問題的方法是:程序中凡是用到中文的地方都以QString::fromLocal8Bit(“中文”)的形式出現。如下爲改進後的程序結果:
在這裏插入圖片描述

在這裏插入圖片描述

情況二

軟件平臺:Windows 10,Qt Creator 4.7.2,CMake 3.13.4

問題描述:運行一個含有中文輸出的cmake項目時,在控制檯中輸出的都是中文亂碼。出現中文亂碼的原因在於,中文版的Windows平臺支持的是GB2312的編碼格式,而Qt Creator默認使用的則是Linux下通用的UTF-8編碼格式,然後,基於Windows平臺的程序控制臺再用GB2312編碼格式來解釋本是UTF-8格式的中文輸出,進而就因爲兩者的編碼格式的不同導致了中文亂碼的輸出。解決問題的思路爲,一是改變Windows系統的編碼格式爲UTF-8,二是把Qt Creator的默認編碼格式改爲GB2312。下面的解決方案遵循思路二。
在這裏插入圖片描述
解決方案:工具=>選項=>文本編輯器=>行爲,把文件編碼那一塊中的默認編碼設爲:GB2312,然後點擊Apply,再點擊OK
在這裏插入圖片描述
把編輯器的默認編碼改爲GB2312後,還要注意一些事項才能輸出中文,注意事項如下:

  • 把代碼string a="你好,中文!";中的中文去掉,如string a="";,其他的也可以,只要保證代碼中沒有中文即可

  • 進入項目所在的目錄,把構建目錄build和項目文件CMakeLists.txt.user刪除掉
    在這裏插入圖片描述

  • 通過Qt Creator打開文件CMakeLists.txt重新構建CMake項目HelloWorld,然後把之前的代碼改回來,即把string a="";改爲string a="你好,中文!";。如此,在控制檯中輸出的中文就不再是亂碼了在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章