1. 程式人生 > >徹底解決QT編碼問題

徹底解決QT編碼問題

字串常量、"中文"是傳統的char型別的窄字串、在使用的時候只需要告訴QString這兩個漢字採用的編碼構造QString。

const char * str = "中文";
QString qstr = str;   //相當於呼叫QString::QString(const char * str)初始化一個QString

概念1:原始檔是有編碼的
"中文" 在不同的編碼下對應不同的二進位制形式
可能在GBK編碼下是:ce d2 ca c7
在Latin-1編碼下是:ba ba d7 d6

概念2:QString內部採用的是Unicode

一個問題,原始碼中假如有4個位元組"\xce\xd2\xca\xc7“該怎麼轉換成Unicode並存儲在QString內。按照GBK、BIG5、Latin-1還是其他方式...
在你不告訴它的情況下,它預設選擇了Latin-1,於是4個字元"ÎÒÊÇ"的unicode碼被存進了QString中。最終,4個Latin字元出現在你期盼看到2中文字元的地方,所謂的亂碼出現了

解決方式

問題很簡單,當你需要從窄字串 char* 轉成Unicode的QString字串的,你需要告訴QString你的這串char* 中究竟是什麼編碼?GBK、BIG5、Latin-1
理想情況就是:將char* 傳給QString時,同時告訴QString自己的編碼是什麼

就像下面的函式一樣,QString的成員函式知道按照何種編碼來處理 C 字串
QString QString::fromAscii ( const char * str, int size = -1 )
QString QString::fromLatin1 ( const char * str, int size = -1
) QString QString::fromLocal8Bit ( const char * str, int size = -1 ) QString QString::fromUtf8 ( const char * str, int size = -1 ) QString 只提供了這幾個成員函式,遠遠滿足不了大家的需求,比如,在簡體中文Windows下,local8Bit是GBK,可是有一個char串是 BIG5 或 Latin-2怎麼辦? 可以使用強大的QTextCodec,首先QTextCodec肯定知道自己所負責的編碼的,當你把一個char串送給它,就能正確將其轉成Unicode QString QTextCodec::toUnicode ( const
char * chars ) const 可是這個呼叫太麻煩了 想直接 QString a= str; QString a(str); 這樣一來肯定沒辦法同時告訴 QString 你的str是何種編碼了,只能通過其他方式了。 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); 設定QString預設採用的編碼。而究竟採用哪一個,一般來說就是原始碼是GBK,就用GBK,原始碼是UTF-8就用UTF-8。但有一個例外,如果你儲存成了帶BOM的UTF-8而且用的微軟的cl編譯器,此時仍是GBK。

總結

QString內部採用的是 Unicode,它可以同時存放GBK中的字元"我是漢字",BIG5中的字元"扂岆犖趼" 以及Latin-1中的字元"ÎÒÊǺº×Ö"。

當你需要從窄字串 char* 轉成Unicode的QString字串的,你需要告訴QString你的這串char* 中究竟是什麼編碼?GBK、BIG5、Latin-1?

在你不告訴它的情況下,它預設選擇了Latin-1,於是8個字元"ÎÒÊǺº×Ö"的unicode碼被存進了QString中。最終,8個Latin字元出現在你期盼看到4中文字元的地方,

所謂的亂碼出現了。

網上有很多方法介紹直接在main.cpp裡設定:

QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForTr(codec);
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);

其實這在某些情況下也是有問題的,因為程式可能讀到系統的中文路徑,或者呼叫中文路徑下的外部程式,這時候如果系統是gb2312就有問題了。

因為中文路徑的編碼是採用utf-8存到QString裡的,系統讀中文路徑解碼的時候採用的卻是系統的gb2312,所以會調不起帶中文路徑的外部程式。

以上問題下面方法可以解決:

QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForTr(codec);
QTextCodec::setCodecForLocale(QTextCodec::codecForLocale()); //設定GBK到本地
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());

對於外部字串編碼解碼全部採用本地編碼。

在QT5中,加上這句,原始檔使用UTF-8編碼,不帶BOM
QApplication a(argc, argv);
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));原文地址