QTextCodec && 字符編碼

    把字符轉換成計算機可以識別的比特流的方法就叫做字符編碼。
 
    顯然,美國人的ASCII碼是不能表示中國文字的,因爲它只能表示256個字符。中國的標準像GB2312,GBK,GB18030 雖然可以表示美國人的文字,但是卻不能表示阿拉伯字符和其它一些象型文字。人們意識到這是文化交流的障礙,於是就制定了Unicode標準。簡言之,Unicode標準就是窮盡這個世界上所有的文字,每個字符對應一個編碼。其實Unicode和GB2312,GBK等一樣,也只是一種編碼標準,只不過它能夠表示所有的文字。從此,如果一個計算機系統想要支持多種語言文字,只要簡單地支持Unicode就可以了。
 
    雖然解決了編碼不能相互表示的大問題,但是還有一個麻煩沒有解決:所謂編碼就是給文字編一個數字。在每個編碼裏,數字與文字是一一對應的,但是在不同的編碼標準可能包含相同的文字,卻被編了不同的數字。於是同一個文字對應了不同的數字。另外同一個數字是否代表着同一個文字呢?顯然不是的,不然,兩種編碼標準就只有包含文字多少的區別了,或者每個文字在兩個編碼對應了相同的數字,那這還是兩個編碼標準嗎?
 
    如今這個世界上以前的標準仍然盛行,特別是Windows仍然使用舊的標準。在中文簡體的Windows上,用記事本寫的文本文件仍然是GBK編碼的。想要在一個使用Unicode的瀏覽器上顯示出文字來依然不行,不同的編碼環境從文件裏讀取的編碼不會變,但是卻表示了不同的文字。怎麼辦呢?很容易想到的辦法是讀取文件內容的時候把GBK編碼轉成Unicode編碼。因爲GBK包含的文字只是Unicode包含的文字的一部分而已,從GBK轉成Unicode應該是沒問題的。反之,從Unicode轉成GBK卻不一定可以。
     另外一種情況是兩種編碼標準差不多,只是每個文字在兩種編碼標準裏對應的編碼不一樣。比如GBK和CJK,兩種編碼標準都包含了大量的中文簡體文字和繁體文字,但是兩種編碼是不一樣的。一個GBK的文本文件想拿到只支持CJK的環境裏閱讀也要在讀取文件的時候從GBK編碼轉成CJK編碼。目前一般採用先把GBK轉成Unicode,然後再從Unicode轉成CJK的間接做法。在上一種情況下我們已經知道:GBK轉成Unicode是可以的,但是Unicode的文字轉成GBK卻不一定可以。但是因爲如果真的不能從Unicode轉到CJK的話,說明那個文字CJK根本不能表示,直接從GBK轉成CJK肯定也不可以。相對於直接從GBK轉成CJK的方式而言,間接的轉碼多了一個步驟,不過形式上比較統一,只要每種編碼都編寫一段與Unicode相互轉換的程序,就可以進行任意編碼的相互轉換。
 
    此外再有就是雖然編碼是一樣的,但是編碼轉換成字節組的方式也是可以有多種方式的;最典型的是Unicode編碼。Unicode編入了很多個字符,而且個數總是在增加,把文字串轉換成Unicode字節組最簡單的辦法就是每個字符用三個字節來表示,因爲Unicode目前爲止大約有100713個字符,這個數字最少需要三個字節才能表示。實際上通常採用的是UTF-8方案。其中,最常使用的128個英文字母用一個字節來表示,中文使用三個字節來表示。還可以使用UTF-16方案,其中英文和中文都使用兩個字節來表示,而其它字符采用四個字節。還有一種UTF-32方案,所有的文字都用四個字節來表示。大多數軟件在內存中使用UTF-16來表示文字,而在硬盤文件或者網絡數據流中使用UTF-8。前者字節數比較固定,比較容易處理,而後者比較節約空間。
 
現在說明一下Qt對於字符編碼的處理。
 
       Qt爲字節流和字符串分別提供了QByteArray和QString兩個類(還有QLatin1String等其他類,但這兩個是最主要的)。當我們涉及到I/O時,比如讀寫文件、讀寫網絡socket、控制檯輸入輸出、讀寫串口... 操作的都是字節流,如果我們此時需要操作的內容是字符串,則需要二者之間的相互轉換。在C和C++中,我們一般都是將 "Hello World!" 這種稱爲字符串。但是就目前而言,當我們提字符串時,一般是指一個Unicode字符串,其由一個一個的Unicode字符構成;當我們提字節流時,是指一個一個的字節。或許我們可以說,ANSI C/C++截止目前只有字節流,而缺乏對字符串的支持。另外各個編譯器對編碼的支持又嚴重不一, Qt爲解決這個問題提供了QTextCodec。
 
      一旦在Qt程序中出現latin1字符集以外的字符,幾乎大家無一例外的會用到 QTextCodec。甚至有不少網友不分青紅皁白,一旦用到中文,就同時使用下面3條指令:
 QTextCodec * textc = QTextCodec::codecForName("GBK");
 1.QTextCodec::setCodecForCStrings(textc);
 2.QTextCodec::setCodecForTr(textc);
 3.QTextCodec::setCodecForLocale(textc);
 這3條指令簡單來說就是爲了實現字符串與字節流之間的轉換(也就是字符的編解碼)。
 
       QString 是不存在中文支持問題的,很多人遇到問題,並不是本身 QString 的問題,而是沒有將自己希望的字符串正確賦給QString。很簡單的問題,"我是中文"這樣寫的時候,它是傳統的char 類型的窄字符串,我們需要的只不過是通過某種方式告訴QString 這四個漢字採用的那種編碼。而問題一般都出在很多用戶對自己當前的編碼沒太多概念。另外文件是有編碼的,但是這種純文本文件卻不會記錄自己採用的編碼,這個是問題的根源。真的是 QString 亂碼了嗎?其實很簡單的一個問題,當你從窄字符串 char* 轉成Unicode的QString字符串的時候,你需要告訴QString你的這串char* 中究竟用的是什麼編碼?GBK、BIG5還是Latin-1。理想情況就是:將char* 傳給QString時,同時告訴QString自己的編碼是什麼;但是QString 提供的成員函數,遠遠滿足不了大家的需求,於是只有採取語句1的辦法。
 
      tr是用來實現國際化的,前提是你爲這個程序提供了翻譯包,但是他需要經過多級函數調用才實現了翻譯操作,是有代價的,所以不該用的時候最好不要用。相比QCoreApplication:: translate,tr大家應該用的更多一些。tr(“中文”);與QString("中文");一樣,你必須告訴tr這個窄字符串是何種編碼?你不告訴它,它就用latin1。於是所謂的亂碼問題就出來了。如何告訴tr你寫的這幾個漢字在磁盤中保存的是何種編碼呢?這正是語句2所做的。如果你的編碼採用的utf8,可以直接使用trUtf8而不必設置setCodecForTr()。
 
       對於語句3應該沒什麼好說的,在絕大多數情況下,我們在代碼中應該都用不到這個函數(默認的system應該比我們所能設置的要好)。
 
 
PS:一個使用QTextCodec類的qt程序,在具有qt開發環境下的windows上運行很正常,而在沒有qt開發環境下的windows上運行,在運行到QTextCodec對象時,就會彈出遇到錯誤。程序裏注消了QTextCodec對象代碼,程序運行正常,但不能處理中文了。

       Qt中帶了很多插件(Plugin),在Qt目錄下的"qt\plugins"下有一個"codecs"的文件夾。下面的文件從文件名就可以區別出來是“簡體中文,繁體中文,日文,韓文”的編碼插件。將該文件夾拷貝到程序所在的目錄,程序運行就正常了(當然,codecs文件下面的".a"文件都可以刪除,".dll"文件也可以把帶"d"的debug版本的刪掉。注意的是一定要把codecs文件夾放在發佈程序的同目錄下,且不要更改目錄名字。)。總之除了Qt運行的Core和Gui等庫,使用QTextCodec類後,程序打包的時候別忘了帶上plugins\codecs。
 
      對一些特殊的處理還要注意是不是帶了相應的插件。這很重要!

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