時至今日,字符串使用unicode已經是不需要理由的常識,但對一些有着悠久歷史的編程語言來說,這仍然是個頭痛的問題。如果拋開第三方庫的支持,C++其實並不能實際有效地支持unicode,即使是utf8。(注:本文討論的是字符串在內存中的編碼方案,而不是文件或網絡數據流。)
STL的string模板誕生時,unicode還是理想中的固定16位編碼。那時,Windows、Java等先后跨躍進unicode時代,而Unix/Linux受限於向后兼容而難以改變。那時Windows上的C++編程主要用用Win32 API,還不流行STL,而Unix/Linux上還基本不支持Unicode。STL的wstring,只是將char模板參數替換成wchar_t,看起來似乎完全合理,其實並沒有經過實踐檢驗。所以,Windows上的wstring至今一直處於實際上不可用的狀態,各種IO時的編碼轉換都有問題;而Linux上的wchar_t是32位,太浪費內存所以完全不值得使用。(最新的標准針對unicode引入了char16_t和char32_t,以及u16string和u32string)
為什么Linux上的wchar_t是32位呢?因為gcc開始支持寬字符的時候,大約也是unicode的字符集突破16位編碼極限的時候。本來預期非常充足的碼位,出乎意料的不夠了,unicode不得不做出調整。調整后,有了三種可選的unicode編碼:
utf32:一個碼位固定4字節,一個碼位表示一個字符編碼。
utf16:兼容之前的16位編碼,一個碼位2字節,但1或2個碼位表示一個字符編碼(所以有可能會有問題)。
utf8:兼容ASCII編碼,一個碼位1字節,但1到6個碼位表示一個字符編碼。(現行標准其實要求最多4個碼位,但出於保障兼容性的原因,5、6個碼位的情況是可能出現的,即使這算無效編碼。)
(除此之外,還有字符組合和修飾符組合的情況,使得碼位到字符的映射更加復雜,在此忽略。)
utf8的出現,讓Linux系統發現了新的機會,既然兼容ASCII,那么只要系統的編碼頁新加一個utf8的,不就支持unicode了么。很自然的,Linux就走了這條路。而Windows卻不支持utf8的編碼頁,這讓很多寫跨平台程序的人對微軟很是不滿。而后,更有人宣稱,Windows、Java、.NET等選錯了unicode編碼,utf8才是王道。
我很希望字符編碼有個完美的解決方案,但很可惜,每當我們試圖讓它變得簡單,它就變得更加復雜。最基本的問題:一個utf8編碼的char數組,只不過是一個字節buffer,在C/C++的標准庫支持下,你根本無法把它當字符串來處理。想要字符串長度?它只能給你字節數,而不是字符數。想要取第n個字符?它只能給你第n個字節。想要把一個字符轉大寫?想判斷一個字符是否是字母?它只接受char類型的字符,也就是說只支持ASCII字符……
即使說對一個不需要操作字符的程序,在C/C++程序里我們總是要為輸入分配buffer的,那么預期輸入n個字符的buffer,應該分配多少字節呢?沒錯,你只能按最大可能n*6+1來分配。對內存臨時分配還好,要是一個數據庫字段,你怎么辦?這時即使是utf32都可能更省存儲空間。
當然,絕大多數問題都可以通過使用一個第三方的unicode庫來解決。如果覺得專門的unicode庫太heavy,至少還有boost的日常解決方案,只要把所有字符串操作替換成專門的函數……(如果安全性對你的程序很重要,你還要了解所用函數在遇到無效編碼時的行為,因為這也是黑客突破安全檢查的一種手段。)
但是,大多數的程序員甚至並不清楚unicode編碼,更不可能了解編碼轉換的復雜性,他們或者習慣了C風格的字節操作,或者來自Java等使用雙字節unicode的語言,做着並非字處理的軟件,所以對學習復雜的unicode編碼系統並無太大興趣。所以,utf8在C/C++里,更象是專家級的解決方案,而並非面向普通開發者。理想情況下,C++可以憑借其強大的抽象和封裝能力,包裝出一個真正基於字符訪問的字符串類(Python3走了這條路,但有很多批評的聲音),然而現實中則很難將其標准化。
那么Windows、Java、.NET、iOS等所使用的utf16呢?本質上,他們的支持都是有缺陷的。因為他們開始時支持的其實是utf16的前身UCS2,每個字符固定2字節,而當utf16出現后,就權當UCS2用,也就是說雙碼位4字節的字符(unicode里稱作BMP以外的字符)會被當作兩個字符處理。如果你的程序真的想要正確支持雙碼位的字符,就要改寫程序,使用高級字符串函數來訪問字符串,而不是直接用下標索引。只是因為BMP以外的字符極其罕用,其程序員並不急需了解這些細節。從正確性角度來說,這並不正確,但從實用角度來說,還算實用。
http://blog.csdn.net/nightmare/article/details/39780931#comments