小時候剛開始學程序設計的時候就為了中文編碼而頭痛,尤其是做JSP的時候。不是頁面顯示不對,就是參數獲取上有問題。記得經常和Vincent兩個人很快把程序架構寫好后,要為了字符編碼問題忙上好久。
在第一次飛法國的飛機上就想過,終于可以不用為了編碼而困擾了。工作后,公司的項目都是英、法、德三種語言,沒有超越Latin1字符集。默認的工作環境也是ISO-8859-1編碼集。一年多以來,倒也是相安無事。
最近,開始了一個新項目。不算很大的工作量,也沒有什么陌生的技術,一開始進展很是順利。但是在實際測試時發現了問題,就是表單數據的字符編碼。這個項目有兩個版本,羅馬尼亞語和土耳其語。這兩種語言都超越了西歐Latin1字符集,卻又分屬于ISO-8859-2和ISO-8859-9兩個不同的編碼集。
其實完全可以全部用UTF-8編碼了事。但是公司的Tomcat和MySQL全局環境都顯式配置為ISO-8859-1,而且在龐大的底層程序中有好幾處都硬編碼成Latin1。更改全局配置是不可能的,也不想冒極大的風險來修改底層類。
最后完全迷失于編碼轉換中……很神奇的是沒有亂碼出現。Latin1以外的字符被轉換成HTML格式編碼了。所以就用了很惡心的方法,把讀入的表單數據從8859-1讀入轉換成UTF-8(HTML <-> UTF是很容易的)后再轉成8859-2/9顯示(由于客戶方終端不支持UTF-8方案,不能直接用輸出Unicode)。盡管8859-1編碼集不支持Latin1字符集以外的字符,但是這層轉換的內部處理還是通過Unicode,不存在信息丟失問題。說白了就是UTF-8 -> ISO。
不過數據庫中的數據卻始終無法正常存儲。數據永遠以亂碼讀出,而且無法轉換。奇怪的是,如果把控制臺編碼換成8859-2/9的話,可以在數據庫中看到正確的數據。但是運行
SELECT HEX(column) FROM table
得到的結果卻是錯誤的。獲得的十六進制編碼是信息經過
8859-1編碼后的Unicode值。這個問題涉及到系統底層類,數據庫配置等多個方面。Rene甚至不知道在數據庫中貯存的到底是什么。
最后的理解是這樣的,底層接口類把數據轉換成8859-1編碼存入數據庫,同樣也以8859-1讀出。SQL請求以字節流返回,這也說明了在控制臺下可以用8859-2/9編碼看到正確結果。但是中間結果由于全局配置的關系,被編碼成8859-1,所以顯示的Unicode值不對。在程序中,由于數據取出后被強制轉換成8859-1編碼,所以造成了信息丟失。就再也找不回Latin1以外的字符了。
最終的解決方案,讓Rene惡心到可以從Montparnasse上跳下來。由于數據在存入數據庫前是正確的,其實在存入時也是正確的。所以打算在存入前,把信息轉成十六進制編碼。理論上應該是可行的,就是會很難看,非常非常難看。