漢字編碼的常識(shí)
我們知道,英文字符一般是以一個(gè)字節(jié)來(lái)表示的,最常用的編碼方法是 ASCII 。但一個(gè)字節(jié)最多只能區(qū)分256個(gè)字符,而漢字成千上萬(wàn),所以現(xiàn)在都以雙字節(jié)來(lái)表示漢字,為了能夠與英文字符分開(kāi),每個(gè)字節(jié)的最高位一定為1,這樣雙字節(jié)最多可以表示64K格字符。我們經(jīng)常碰到的編碼方式有 GB2312、BIG5、UNICODE 等。關(guān)于具體編碼方式的詳細(xì)資料,有興趣的讀者可以查閱相關(guān)資料。我膚淺談一下和我們關(guān)系密切的 GB2312 和 UNICODE。GB2312 碼,中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn)漢字信息交換用編碼,是一個(gè)由中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn)總局發(fā)布的關(guān)于簡(jiǎn)化漢字的編碼,通行于中國(guó)大陸地區(qū)及新加坡,簡(jiǎn)稱國(guó)標(biāo)碼。兩個(gè)字節(jié)中,第一個(gè)字節(jié)(高字節(jié))的值為區(qū)號(hào)值加32(20H),第二個(gè)字節(jié)(低字節(jié))的值為位號(hào)值加32(20H),用這兩個(gè)值來(lái)表示一個(gè)漢字的編碼。UNICODE 碼是微軟提出的解決多國(guó)字符問(wèn)題的多字節(jié)等長(zhǎng)編碼,它對(duì)英文字符采取前面加“0”字節(jié)的策略實(shí)現(xiàn)等長(zhǎng)兼容。如 “A” 的 ASCII 碼為0x41,UNICODE 就為0x00,0x41。利用特殊的工具各種編碼之間可以互相轉(zhuǎn)換。
事實(shí)上,Java的中文問(wèn)題都是由于Java應(yīng)用所采用的缺省編碼格式與目標(biāo)或者應(yīng)用所要讀入字符的編碼格式不同而造成的(具體參見(jiàn)文獻(xiàn)1)。對(duì)于如何解決Java的中文問(wèn)題,通常有四種方法:
1) 選擇JDK的中文本地化版本。盡管Java2 JDK的中文本地化版本(http://java.sun.com/products/jdk/1.2/chinesejdk.html)并不是一個(gè)官方的版本,Sun公司也沒(méi)有承諾會(huì)對(duì)該本地化版本進(jìn)行升級(jí),但其仍不失為一個(gè)Java中文問(wèn)題的解決方案。
2) 選擇合適的編譯參數(shù)。對(duì)于Java的國(guó)際版本來(lái)講,我們也可以在編譯Java應(yīng)用的時(shí)候通過(guò)指定確定的編碼機(jī)制來(lái)實(shí)現(xiàn)其編譯結(jié)果對(duì)中文的支持。例如,對(duì)于需要支持繁體中文和簡(jiǎn)體中文應(yīng)用可以通過(guò)javac -encoding big5 sourcefile.java 和javac -encoding gb2312 sourcefile.java來(lái)編譯源程序。
3) 通過(guò)編程的方式實(shí)現(xiàn)字符編碼的轉(zhuǎn)換代碼。通過(guò)編程的方式來(lái)解決Java的中文問(wèn)題,已經(jīng)成為了一種較為普遍的做法。下面就是一種最常見(jiàn)的字符編碼轉(zhuǎn)換函數(shù),其將字符的編碼格式轉(zhuǎn)換為中文Windows系統(tǒng)的GBK編碼形式。
4) 定義字符輸出集。對(duì)于JSP應(yīng)用,我們可以通過(guò)<%@ page contentType="text/html; charset=GBK" %>或<%@ page contentType="text/html; charset=GB2312" %>來(lái)定義JSP頁(yè)面的字符輸出集。當(dāng)然,我們也可以通過(guò)HTML的標(biāo)記<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">來(lái)定義字符的輸出集。
分析的原則
總的說(shuō)來(lái),所有解決Java中文處理的方法都不是很復(fù)雜。相反的是,由于Java技術(shù)特別是J2EE技術(shù)涉及的內(nèi)容繁多,各種Web服務(wù)器、應(yīng)用服務(wù)器以及JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng)等參差不齊,所以如何正確而及時(shí)的發(fā)現(xiàn)應(yīng)用的中文處理問(wèn)題則變得相對(duì)復(fù)雜的多。那么我們?nèi)绾蝸?lái)發(fā)現(xiàn)這些問(wèn)題呢?
通常,Java處理中文時(shí)所產(chǎn)生的問(wèn)題都是由于用戶的Java應(yīng)用所采用的缺省編碼格式與目標(biāo)或者應(yīng)用所要讀入字符的編碼格式不同而造成的,而引起這些不同的一個(gè)主要原因就是用戶的Java應(yīng)用與其它應(yīng)用進(jìn)行了編碼格式不匹配的數(shù)據(jù)交換(包括直接或間接的數(shù)據(jù)輸入、輸出)。所以,為了及時(shí)發(fā)現(xiàn)問(wèn)題,我們可以由這一點(diǎn)入手,根據(jù)以下的原則對(duì)應(yīng)用進(jìn)行分析:
Java 的基本類也可能存在問(wèn)題。由于國(guó)際化的工作并不是在國(guó)內(nèi)完成的,所以在這些基本類發(fā)布之前,沒(méi)有經(jīng)過(guò)嚴(yán)格的測(cè)試,所以對(duì)中文字符的支持并不像 Java Soft 所聲稱的那樣完美。前不久,我的一位技術(shù)上的朋友發(fā)信給我說(shuō),他終于找到了 Java Servlet 中文問(wèn)題的根源。兩周以來(lái),他一直為 Java Servlet 的中文問(wèn)題所困擾,因?yàn)槊棵鎸?duì)一個(gè)含有中文字符的字符串都必須進(jìn)行強(qiáng)制轉(zhuǎn)換才能夠得到正確的結(jié)果(這好象是大家公認(rèn)的唯一的解決辦法)。后來(lái),他確實(shí)不想如此繼續(xù)安分下去了,因?yàn)檫@樣的事情確實(shí)不應(yīng)該是高級(jí)程序員所要做的工作,他就找出 Servlet 解碼的源代碼進(jìn)行分析,因?yàn)樗麘岩蓡?wèn)題就出在解碼這部分。經(jīng)過(guò)四個(gè)小時(shí)的奮斗,他終于找到了問(wèn)題的根源所在。原來(lái)他的懷疑是正確的, Servlet 的解碼部分完全沒(méi)有考慮雙字節(jié),直接把 %XX 當(dāng)作一個(gè)字符。(原來(lái) Java Soft 也會(huì)犯這幺低級(jí)的錯(cuò)誤!)
如果你對(duì)這個(gè)問(wèn)題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟 對(duì)Servlet.jar 進(jìn)行修改:
找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將 sb(StringBuffer) 復(fù)制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解碼了:
HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者
form=HttpUtils.parsePostData(……)
千萬(wàn)別忘了編譯后放到 Servlet.jar 里面。java中文問(wèn)題詳解http://www.cn-java.com/target/news.php?news_id=210關(guān)于Java中文問(wèn)題的幾條分析原則http://www-900.ibm.com/developerWorks/cn/java/l-javachinese/index.shtml全方位解決xml中文問(wèn)題http://www.csdn.net/develop/read_article.asp?id=18901servlet 中的漢字編碼問(wèn)題http://www-900.ibm.com/developerWorks/cn/java/jsp_dbcsz/index.shtmlJava程序的國(guó)際化和本地化介紹http://www-900.ibm.com/developerWorks/cn/java/joy-i18n/index.shtmlJava 編程技術(shù)中漢字問(wèn)題的分析及解決http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtmlUnicode專題http://www-900.ibm.com/developerWorks/cn/theme/unicode.shtml這里也有篇專家寫的文章:http://www.javaworld.com/javaworld/jw-04-2004/jw-0419-multibytes.html
Powered by: BlogJava Copyright © 橘子