始終逃不過的字符編碼問題
小時候剛開始學(xué)程序設(shè)計的時候就為了中文編碼而頭痛,尤其是做JSP的時候。不是頁面顯示不對,就是參數(shù)獲取上有問題。記得經(jīng)常和Vincent兩個人很快把程序架構(gòu)寫好后,要為了字符編碼問題忙上好久。
在第一次飛法國的飛機(jī)上就想過,終于可以不用為了編碼而困擾了。工作后,公司的項目都是英、法、德三種語言,沒有超越Latin1字符集。默認(rèn)的工作環(huán)境也是ISO-8859-1編碼集。一年多以來,倒也是相安無事。
最近,開始了一個新項目。不算很大的工作量,也沒有什么陌生的技術(shù),一開始進(jìn)展很是順利。但是在實際測試時發(fā)現(xiàn)了問題,就是表單數(shù)據(jù)的字符編碼。這個項目有兩個版本,羅馬尼亞語和土耳其語。這兩種語言都超越了西歐Latin1字符集,卻又分屬于ISO-8859-2和ISO-8859-9兩個不同的編碼集。
其實完全可以全部用UTF-8編碼了事。但是公司的Tomcat和MySQL全局環(huán)境都顯式配置為ISO-8859-1,而且在龐大的底層程序中有好幾處都硬編碼成Latin1。更改全局配置是不可能的,也不想冒極大的風(fēng)險來修改底層類。
最后完全迷失于編碼轉(zhuǎn)換中……很神奇的是沒有亂碼出現(xiàn)。Latin1以外的字符被轉(zhuǎn)換成HTML格式編碼了。所以就用了很惡心的方法,把讀入的表單數(shù)據(jù)從8859-1讀入轉(zhuǎn)換成UTF-8(HTML <-> UTF是很容易的)后再轉(zhuǎn)成8859-2/9顯示(由于客戶方終端不支持UTF-8方案,不能直接用輸出Unicode)。盡管8859-1編碼集不支持Latin1字符集以外的字符,但是這層轉(zhuǎn)換的內(nèi)部處理還是通過Unicode,不存在信息丟失問題。說白了就是UTF-8 -> ISO。
不過數(shù)據(jù)庫中的數(shù)據(jù)卻始終無法正常存儲。數(shù)據(jù)永遠(yuǎn)以亂碼讀出,而且無法轉(zhuǎn)換。奇怪的是,如果把控制臺編碼換成8859-2/9的話,可以在數(shù)據(jù)庫中看到正確的數(shù)據(jù)。但是運(yùn)行

得到的結(jié)果卻是錯誤的。獲得的十六進(jìn)制編碼是信息經(jīng)過
8859-1編碼后的Unicode值。這個問題涉及到系統(tǒng)底層類,數(shù)據(jù)庫配置等多個方面。Rene甚至不知道在數(shù)據(jù)庫中貯存的到底是什么。最后的理解是這樣的,底層接口類把數(shù)據(jù)轉(zhuǎn)換成8859-1編碼存入數(shù)據(jù)庫,同樣也以8859-1讀出。SQL請求以字節(jié)流返回,這也說明了在控制臺下可以用8859-2/9編碼看到正確結(jié)果。但是中間結(jié)果由于全局配置的關(guān)系,被編碼成8859-1,所以顯示的Unicode值不對。在程序中,由于數(shù)據(jù)取出后被強(qiáng)制轉(zhuǎn)換成8859-1編碼,所以造成了信息丟失。就再也找不回Latin1以外的字符了。
最終的解決方案,讓Rene惡心到可以從Montparnasse上跳下來。由于數(shù)據(jù)在存入數(shù)據(jù)庫前是正確的,其實在存入時也是正確的。所以打算在存入前,把信息轉(zhuǎn)成十六進(jìn)制編碼。理論上應(yīng)該是可行的,就是會很難看,非常非常難看。
posted on 2009-11-05 00:24 Rene 閱讀(245) 評論(0) 編輯 收藏 所屬分類: Programming