徹底解決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"));