徹底解決Qt中文亂碼以及漢字編碼的問題(UTF-8/GBK)


尊重作者,支持原創,如需轉載,請附上原地址:https://blog.csdn.net/libaineu2004/article/details/19245205

 

一、Qt Creator環境設置

1、cpp或h文件從window上傳到Ubuntu后會顯示亂碼,原因是因為ubuntu環境設置默認是utf-8,Windows默認都是GBK.

我們使用的Windows系統本地字符集編碼為GBK。

2、Windows環境下,Qt Creator,菜單->工具->選項->文本編輯器->行為->文件編碼->默認編碼,常用的選項有以下幾個:

System(簡體中文windows系統默認指的是GBK編碼)

GBK/windows-936-2000/CP936/MS936/windows-936

UTF-8

 

二、編碼知識科普
Qt常見的兩種編碼是:UTF-8和GBK
★UTF-8:Unicode TransformationFormat-8bit,允許含BOM,但通常不含BOM。是用以解決國際上字符的一種多字節編碼,它對英文使用8位(即一個字節),中文使用24為(三個字節)來編碼。UTF-8包含全世界所有國家需要用到的字符,是國際編碼,通用性強。UTF-8編碼的文字可以在各國支持UTF8字符集的瀏覽器上顯示。如果是UTF8編碼,則在外國人的英文IE上也能顯示中文,他們無需下載IE的中文語言支持包。
★GBK是國家標准GB2312基礎上擴容后兼容GB2312的標准。GBK的文字編碼是用雙字節來表示的,即不論中、英文字符均使用雙字節來表示,為了區分中文,將其最高位都設定成1。GBK包含全部中文字符,是國家編碼,通用性比UTF8差,不過UTF8占用的數據庫比GBD大。GBK是GB2312的擴展,除了兼容GB2312外,它還能顯示繁體中文,還有日文的假名。
★GBK、GB2312等與UTF8之間都必須通過Unicode編碼才能相互轉換:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312
★在簡體中文windows系統下,ANSI編碼代表GBK/GB2312編碼,ANSI通常使用0x80~0xFF范圍的2個字節來表示1個中文字符。0x00~0x7F之間的字符,依舊是1個字節代表1個字符。Unicode(UTF-16)編碼則所有字符都用2個字節表示。

 

三、編碼轉換

Windows自帶的記事本,無法查看UTF-8編碼的文件到底有無BOM,需要使用其他文件編輯器,比如EditPlus或者SublimeText。
UTF-8與ANSI(即GBK)的互轉,可以使用EditPlus工具"文件另存為"或者Encodersoft編碼轉換工具對.cpp和.h源文件文本進行批量轉換.

 

四、QString顯示中文亂碼的原因

我們使用的Windows系統本地字符編碼(Local字符集)為GBK。編譯器分析出源文件字符編碼之后,會進行解碼再編碼,將源字符集轉碼成執行字符集。執行字符集一般默認為使用本地字符編碼(Local字符集)。

Qt5可以設置Local字符集,GBK/UTF-8

QTextCodec *codec = QTextCodec::codecForName("UTF-8");//或者"GBK",不分大小寫
QTextCodec::setCodecForLocale(codec);

Qt5中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就會出現亂碼。)
 

五、Qt編碼指定
Qt需要在main()函數指定使用的字符編碼:

#include <QTextCodec>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

//設置中文編碼

a.setFont(QFont("Microsoft Yahei", 9));
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("GBK");
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec);
#endif
}

這里只列舉大家最常用的3個編譯器(微軟VC++的cl編譯器,Mingw中的g++,Linux下的g++),源代碼分別采用GBK和無BOM的UTF-8以及有BOM的UTF-8這3種編碼進行保存,發生的現象如下表所示。

 

如果您使用的是Visual C++編譯器,則默認情況下不會將您的源代碼視為utf-8編碼。除非有BOM,否則它將使用您當前的代碼頁進行解釋。就是說,當使用Visual C++編譯程序的時候,它會分析源文件采用何種編碼,有BOM標識符則可以正確識別其編碼是UTF-8,若沒有BOM標識符則認為其使用本地字符集編碼(Local字符集)。Local字符集是什么?取決於你的設置QTextCodec *codec = QTextCodec::codecForName(???);
如果源文件是UTF-8+BOM的編碼方式,還需要在頭文件加入

#if defined(_MSC_VER) && (_MSC_VER >= 1600) 
# pragma execution_character_set("utf-8") 
#endif

或者添加QMAKE_CXXFLAGS += /utf-8到您的.pro文件中。

如果源文件是UTF-8+無BOM的編碼方式,則一定不能加#pragma execution_character_set(“utf-8”),不然會產生亂碼。
 

六、測試案例

案例1、中文字符串測試

#include <QApplication>
#include <QTextCodec>
#include <QPushButton>
#include <QDebug>
#include <QString>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("gbk");
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif

QString str(QObject::tr("1中文"));
qDebug() << str;
qDebug() << QStringLiteral("2中文");
qDebug() << QString::fromLatin1("3中文");
qDebug() << QString::fromLocal8Bit("4中文");
qDebug() << QString::fromUtf8("5中文");
qDebug() << QString::fromWCharArray(L"6中文");

return a.exec();
}
當QTextCodec::codecForName("utf-8");時,

QString::fromLocal8Bit和QString::fromUtf8是等效的。

當QTextCodec::codecForName("gbk");時,

QString::fromLocal8Bit和QString::fromUtf8是不等效的。

案例2、QCom跨平台串口調試助手(http://www.qter.org/?page_id=203)
源代碼qcom\mainwindow.cpp,aboutdialog.cpp等文件用的是UTF-8編碼(無BOM);但是qcom\qextserial\*.*文件用的是ANSI編碼.在linux環境編譯完全OK.
筆者Windows環境的Qt Creator+微軟VC++編譯器,環境設置用的是ANSI(即GBK)編碼.編譯源文件會報錯.
錯誤提示"fatal error C1018: 意外的 #elif".

解決方法由兩種:

方法1:

 

把qcom\的所有cpp和h文件都用工具轉換成ANSI編碼,main()函數使用QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));

方法2:

先把Qt Creator環境設置用的是UTF-8編碼,

 

再把qcom\的所有cpp和h文件都用工具轉換成UTF-8+BOM編碼,請注意,如果文件轉換成UTF-8(無BOM),編譯仍會失敗.main()函數使用QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));//注意,此處仍是"GBK",不是"UTF-8"
重新編譯,OK!

其它:

 

七、結論

Windows環境下,Qt Creator+微軟VC++編譯器,新建工程,

1、如果該工程不需要跨平台使用(只在win),那么工程設置請使用GBK的編碼方式.

2、如果該工程要跨平台使用(win+linux),那么工程設置請使用UTF-8+BOM的編碼方式.

 

另外,還需要在頭文件加入

#if defined(_MSC_VER) && (_MSC_VER >= 1600)
# pragma execution_character_set("utf-8")
#endif
或者添加QMAKE_CXXFLAGS += /utf-8到您的.pro文件中。

3、Linux環境下,Qt Creator+gcc,新建工程,

沒有GBK編碼可選,默認是UTF-8(無BOM)編碼方式,考慮到跨平台,建議選擇UTF-8+BOM的編碼方式.

x、參考文獻

Qt官網文檔 

https://wiki.qt.io/Strings_and_encodings_in_Qt

https://doc.qt.io/qt-5/unicode.html

ASCII,Unicode和UTF-8完全搞清楚 https://blog.csdn.net/Deft_MKJing/article/details/79460485

Qt中文亂碼原因及解決方案 https://blog.csdn.net/qq_35905572/article/details/95042444

Qt中文亂碼問題 http://blog.csdn.net/brave_heart_lxl/article/details/7186631

尊重作者,支持原創,如需轉載,請附上原地址:https://blog.csdn.net/libaineu2004/article/details/19245205
————————————————
版權聲明:本文為CSDN博主「libaineu2004」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/libaineu2004/article/details/19245205


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM