![]() |
現(xiàn)在 Java 編程語言已經(jīng)廣泛應(yīng)用于互聯(lián)網(wǎng)世界,早在 Sun 公司開發(fā) Java 語言的時候,就已經(jīng)考慮到對非英文字符的支持了。Sun 公司公布的 Java 運行環(huán)境(JRE)本身就分英文版和國際版,但只有國際版才支持非英文字符。不過在 Java 編程語言的應(yīng)用中,對中文字符的支持并非如同 Java Soft 的標準規(guī)范中所宣稱的那樣完美,因為中文字符集不只一個,而且不同的操作系統(tǒng)對中文字符的支持也不盡相同,所以會有許多和漢字編碼處理有關(guān)的問題在我們進行應(yīng)用開發(fā)中困擾著我們。有很多關(guān)于這些問題的解答,但都比較瑣碎,并不能夠滿足大家迫切解決問題的愿望,關(guān)于 Java 中文問題的系統(tǒng)研究并不多,本文從漢字編碼常識出發(fā),分析 Java 中文問題,希望對大家解決這個問題有所幫助。 漢字編碼的常識 Java 中文問題的初步認識 String sEnglish = “apple”; String sChinese = “蘋果”; String s = “蘋果 apple ”; sEnglish 的長度是5,sChinese的長度是4,而 s 默認的長度是14。對于 sEnglish來說, Java 中的各個類都支持得非常好,肯定能夠正確顯示。但對于 sChinese 和 s 來說,雖然 Java Soft 聲明 Java 的基本類已經(jīng)考慮到對多國字符的支持(默認 UNICODE 編碼),但是如果操作系統(tǒng)的默認編碼不是 UNICODE ,而是國標碼等。從 Java 源代碼到得到正確的結(jié)果,要經(jīng)過 “Java 源代碼-> Java 字節(jié)碼-> ;虛擬機->操作系統(tǒng)->顯示設(shè)備”的過程。在上述過程中的每一步驟,我們都必須正確地處理漢字的編碼,才能夠使最終的顯示結(jié)果正確。 “ Java 源代碼-> Java 字節(jié)碼”,標準的 Java 編譯器 javac 使用的字符集是系統(tǒng)默認的字符集,比如在中文 Windows 操作系統(tǒng)上就是 GBK ,而在 Linux 操作系統(tǒng)上就是ISO-8859-1,所以大家會發(fā)現(xiàn)在 Linux 操作系統(tǒng)上編譯的類中源文件中的中文字符都出了問題,解決的辦法就是在編譯的時候添加 encoding 參數(shù),這樣才能夠與平臺無關(guān)。用法是 javac ?Cencoding GBK。 “ Java 字節(jié)碼->虛擬機->操作系統(tǒng)”, Java 運行環(huán)境 (JRE) 分英文版和國際版,但只有國際版才支持非英文字符。 Java 開發(fā)工具包 (JDK) 肯定支持多國字符,但并非所有的計算機用戶都安裝了 JDK 。很多操作系統(tǒng)及應(yīng)用軟件為了能夠更好的支持 Java ,都內(nèi)嵌了 JRE 的國際版本,為自己支持多國字符提供了方便。 “操作系統(tǒng)->顯示設(shè)備”,對于漢字來說,操作系統(tǒng)必須支持并能夠顯示它。英文操作系統(tǒng)如果不搭配特殊的應(yīng)用軟件的話,是肯定不能夠顯示中文的。 還有一個問題,就是在 Java 編程過程中,對中文字符進行正確的編碼轉(zhuǎn)換。例如,向網(wǎng)頁輸出中文字符串的時候,不論你是用 out.println(string);還是用 <%=string%>,都必須作 UNICODE 到 GBK 的轉(zhuǎn)換,或者手動,或者自動。在 JSP 1.0中,可以定義輸出字符集,從而實現(xiàn)內(nèi)碼的自動轉(zhuǎn)換。用法是 <%@page contentType=”text/html;charset=gb2312” %> 但是在一些 JSP 版本中并沒有提供對輸出字符集的支持,(例如 JSP 0.92),這就需要手動編碼輸出了,方法非常多。最常用的方法是 String s1 = request.getParameter(“keyword”); String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”); getBytes 方法用于將中文字符以“ISO-8859-1”編碼方式轉(zhuǎn)化成字節(jié)數(shù)組,而“GBK” 是目標編碼方式。我們從以ISO-8859-1方式編碼的數(shù)據(jù)庫中讀出中文字符串 s1 ,經(jīng)過上述轉(zhuǎn)換過程,在支持 GBK 字符集的操作系統(tǒng)和應(yīng)用軟件中就能夠正確顯示中文字符串 s2 。
.CLASS 文件存放在服務(wù)器端,由客戶端的瀏覽器運行 APPLET , APPLET 只起調(diào)入 FRAME 類等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。 I.用 JDBC 執(zhí)行 SELECT 語句從服務(wù)器端讀取數(shù)據(jù)(中文)后,將數(shù)據(jù)用 APPEND 方法加到 TextArea(TA) ,不能正確顯示。但加到 List 中時,大部分漢字卻可正確顯示。 將數(shù)據(jù)按“ISO-8859-1” 編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按系統(tǒng)缺省編碼方式 (Default Character Encoding) 轉(zhuǎn)化為 STRING ,即可在 TA 和 List 中正確顯示。 程序段如下:
在轉(zhuǎn)換字符串時不采用系統(tǒng)默認編碼方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 兩種情況下,從數(shù)據(jù)庫取數(shù)據(jù)都沒有問題。 II.處理方式與“取中文”相逆,先將 SQL 語句按系統(tǒng)缺省編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按“ISO-8859-1”編碼方式轉(zhuǎn)化為 STRING ,最后送去執(zhí)行,則中文信息可正確寫入數(shù)據(jù)庫。 程序段如下:
問題:如果客戶機上存在 CLASSPATH 指向 JDK 的 CLASSES.ZIP 時(稱為 A 情況),上述程序代碼可正確執(zhí)行。但是如果客戶機只有瀏覽器,而沒有 JDK 和 CLASSPATH 時(稱為 B 情況),則漢字無法正確轉(zhuǎn)換。 我們的分析: 1.經(jīng)過測試,在 A 情況下,程序運行時系統(tǒng)的缺省編碼方式為 GBK 或者 GB2312 。在 B 情況下,程序啟動時瀏覽器的 JAVA 控制臺中出現(xiàn)如下錯誤信息:
然后系統(tǒng)的缺省編碼方式為“8859-1”。 2.如果在轉(zhuǎn)換字符串時不采用系統(tǒng)缺省編碼方式,而是直接采用 “GBK” 或“GB2312”,則在 A 情況下程序仍然可正常運行,在 B 情況下,系統(tǒng)出現(xiàn)錯誤:
3.在客戶機上,把 JDK 的 CLASSES.ZIP 解壓后,放在另一個目錄中, CLASSPATH 只包含該目錄。然后一邊逐步刪除該目錄中的 .CLASS 文件,另一邊運行測試程序,最后發(fā)現(xiàn)在一千多個 CLASS 文件中,只有一個是必不可少的,該文件是:
將該文件拷到服務(wù)器端和其它的類放在一起,并在程序的開頭 IMPORT 它,在 B 情況下程序仍然無法正常運行。 4.在 A 情況下,如果在 CLASSPTH 中去掉 sun.io.CharToByteDoubleByte.class ,則程序運行時測得默認編碼方式為“8859-1”,否則為 “GBK” 或 “GB2312” 。 如果 JDK 的版本為1.2以上的話,在 B 情況下遇到的問題得到了很好的解決,測試的步驟同上,有興趣的讀者可以嘗試一下。 Java 中文問題的根源分析及解決 類 PoorChinese 的源代碼:
執(zhí)行 java PoorChinese 后,我們會得到: 系統(tǒng)變量 file.encoding 的值為 GBK ,user.language 的值為 zh , user.region 的值為 CN ,這些系統(tǒng)變量的值決定了系統(tǒng)默認的編碼方式是 GBK 。 在上述系統(tǒng)中,下面的代碼將 GB2312 文件轉(zhuǎn)換成 Big5 文件,它們能夠幫助我們理解 Java 中漢字編碼的轉(zhuǎn)化:
編碼轉(zhuǎn)化的過程如下: GB2312------------------>Unicode------------->Big5 執(zhí)行 java gb2big5 gb.txt big5.txt ,如果 gb.txt 的內(nèi)容是“今天星期三”,則得到的文件 big5.txt 中的字符能夠正確顯示;而如果 gb.txt 的內(nèi)容是“情人節(jié)快樂”,則得到的文件 big5.txt 中對應(yīng)于“節(jié)”和“樂”的字符都是符號“?”(0x3F),可見 sun.io.ByteToCharGB2312 和 sun.io.CharToByteBig5 這兩個基本類并沒有編好。 正如上例一樣, Java 的基本類也可能存在問題。由于國際化的工作并不是在國內(nèi)完成的,所以在這些基本類發(fā)布之前,沒有經(jīng)過嚴格的測試,所以對中文字符的支持并不像 Java Soft 所聲稱的那樣完美。前不久,我的一位技術(shù)上的朋友發(fā)信給我說,他終于找到了 Java Servlet 中文問題的根源。兩周以來,他一直為 Java Servlet 的中文問題所困擾,因為每面對一個含有中文字符的字符串都必須進行強制轉(zhuǎn)換才能夠得到正確的結(jié)果(這好象是大家公認的唯一的解決辦法)。后來,他確實不想如此繼續(xù)安分下去了,因為這樣的事情確實不應(yīng)該是高級程序員所要做的工作,他就找出 Servlet 解碼的源代碼進行分析,因為他懷疑問題就出在解碼這部分。經(jīng)過四個小時的奮斗,他終于找到了問題的根源所在。原來他的懷疑是正確的, Servlet 的解碼部分完全沒有考慮雙字節(jié),直接把 %XX 當作一個字符。(原來 Java Soft 也會犯這幺低級的錯誤!) 如果你對這個問題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟 對Servlet.jar 進行修改: 找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將 sb(StringBuffer) 復(fù)制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解碼了: HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者 form=HttpUtils.parsePostData(……) 千萬別忘了編譯后放到 Servlet.jar 里面。 Java 編程語言成長于網(wǎng)絡(luò)世界,這就要求 Java 對多國字符有很好的支持。 Java 編程語言適應(yīng)了計算的網(wǎng)絡(luò)化的需求,為它能夠在網(wǎng)絡(luò)世界迅速成長奠定了堅實的基礎(chǔ)。 Java 的締造者 (Java Soft) 已經(jīng)考慮到 Java 編程語言對多國字符的支持,只是現(xiàn)在的解決方案有很多缺陷在里面,需要我們付諸一些補償性的措施。而世界標準化組織也在努力把人類所有的文字統(tǒng)一在一種編碼之中,其中一種方案是 ISO10646 ,它用四個字節(jié)來表示一個字符。當然,在這種方案未被采用之前,還是希望 Java Soft 能夠嚴格地測試它的產(chǎn)品,為用戶帶來更多的方便。 附一個用于從數(shù)據(jù)庫和網(wǎng)絡(luò)中取出 中文亂碼的處理函數(shù),入?yún)⑹怯袉栴}的字符串,出參是問題已經(jīng)解決了的字符串。
|
只有注冊用戶登錄后才能發(fā)表評論。 | ||
![]() |
||
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關(guān)文章:
|
||