<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    hengheng123456789

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      297 Posts :: 68 Stories :: 144 Comments :: 0 Trackbacks
     

    Java 編程技術(shù)中漢字問(wèn)題的分析及解決

    現(xiàn)在 Java 編程語(yǔ)言已經(jīng)廣泛應(yīng)用于互聯(lián)網(wǎng)世界,早在 Sun 公司開(kāi)發(fā) Java 語(yǔ)言的時(shí)候,就已經(jīng)考慮到對(duì)非英文字符的支持了。Sun 公司公布的 Java 運(yùn)行環(huán)境(JRE)本身就分英文版和國(guó)際版,但只有國(guó)際版才支持非英文字符。不過(guò)在 Java 編程語(yǔ)言的應(yīng)用中,對(duì)中文字符的支持并非如同 Java Soft 的標(biāo)準(zhǔn)規(guī)范中所宣稱的那樣完美,因?yàn)橹形淖址恢灰粋€(gè),而且不同的操作系統(tǒng)對(duì)中文字符的支持也不盡相同,所以會(huì)有許多和漢字編碼處理有關(guān)的問(wèn)題在我們進(jìn)行應(yīng)用開(kāi)發(fā)中困擾著我們。有很多關(guān)于這些問(wèn)題的解答,但都比較瑣碎,并不能夠滿足大家迫切解決問(wèn)題的愿望,關(guān)于 Java 中文問(wèn)題的系統(tǒng)研究并不多,本文從漢字編碼常識(shí)出發(fā),分析 Java 中文問(wèn)題,希望對(duì)大家解決這個(gè)問(wèn)題有所幫助。

    漢字編碼的常識(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)常碰到的編碼方式有 GB2312BIG5UNICODE 等。關(guān)于具體編碼方式的詳細(xì)資料,有興趣的讀者可以查閱相關(guān)資料。我膚淺談一下和我們關(guān)系密切的 GB2312 UNICODEGB2312 碼,中華人民共和國(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)值加3220H),第二個(gè)字節(jié)(低字節(jié))的值為位號(hào)值加3220H),用這兩個(gè)值來(lái)表示一個(gè)漢字的編碼。UNICODE 碼是微軟提出的解決多國(guó)字符問(wèn)題的多字節(jié)等長(zhǎng)編碼,它對(duì)英文字符采取前面加“0”字節(jié)的策略實(shí)現(xiàn)等長(zhǎng)兼容。如 A ASCII 碼為0x41UNICODE 就為0x000x41。利用特殊的工具各種編碼之間可以互相轉(zhuǎn)換。

    Java 中文問(wèn)題的初步認(rèn)識(shí)

    我們基于 Java 編程語(yǔ)言進(jìn)行應(yīng)用開(kāi)發(fā)時(shí),不可避免地要處理中文。Java 編程語(yǔ)言默認(rèn)的編碼方式是 UNICODE,而我們通常使用的數(shù)據(jù)庫(kù)及文件都是基于 GB2312 編碼的,我們經(jīng)常碰到這樣的情況:瀏覽基于 JSP 技術(shù)的網(wǎng)站看到的是亂碼,文件打開(kāi)后看到的也是亂碼,被 Java 修改過(guò)的數(shù)據(jù)庫(kù)的內(nèi)容在別的場(chǎng)合應(yīng)用時(shí)無(wú)法繼續(xù)正確地提供信息。

    String sEnglish = “apple”;

    String sChinese = “蘋(píng)果”;

    String s = “蘋(píng)果 apple ;

    sEnglish 的長(zhǎng)度是5sChinese的長(zhǎng)度是4,而 s 默認(rèn)的長(zhǎng)度是14。對(duì)于 sEnglish來(lái)說(shuō), Java 中的各個(gè)類都支持得非常好,肯定能夠正確顯示。但對(duì)于 sChinese s 來(lái)說(shuō),雖然 Java Soft 聲明 Java 的基本類已經(jīng)考慮到對(duì)多國(guó)字符的支持(默認(rèn) UNICODE 編碼),但是如果操作系統(tǒng)的默認(rèn)編碼不是 UNICODE ,而是國(guó)標(biāo)碼等。從 Java 源代碼到得到正確的結(jié)果,要經(jīng)過(guò) Java 源代碼-> Java 字節(jié)碼-> ;虛擬機(jī)->操作系統(tǒng)->顯示設(shè)備”的過(guò)程。在上述過(guò)程中的每一步驟,我們都必須正確地處理漢字的編碼,才能夠使最終的顯示結(jié)果正確。

    Java 源代碼-> Java 字節(jié)碼”,標(biāo)準(zhǔn)的 Java 編譯器 javac 使用的字符集是系統(tǒng)默認(rèn)的字符集,比如在中文 Windows 操作系統(tǒng)上就是 GBK ,而在 Linux 操作系統(tǒng)上就是ISO-8859-1,所以大家會(huì)發(fā)現(xiàn)在 Linux 操作系統(tǒng)上編譯的類中源文件中的中文字符都出了問(wèn)題,解決的辦法就是在編譯的時(shí)候添加 encoding 參數(shù),這樣才能夠與平臺(tái)無(wú)關(guān)。用法是

    javac ?Cencoding GBK

    Java 字節(jié)碼->虛擬機(jī)->操作系統(tǒng)”, Java 運(yùn)行環(huán)境 JRE 分英文版和國(guó)際版,但只有國(guó)際版才支持非英文字符。 Java 開(kāi)發(fā)工具包 JDK 肯定支持多國(guó)字符,但并非所有的計(jì)算機(jī)用戶都安裝了 JDK 。很多操作系統(tǒng)及應(yīng)用軟件為了能夠更好的支持 Java ,都內(nèi)嵌了 JRE 的國(guó)際版本,為自己支持多國(guó)字符提供了方便。

    “操作系統(tǒng)->顯示設(shè)備”,對(duì)于漢字來(lái)說(shuō),操作系統(tǒng)必須支持并能夠顯示它。英文操作系統(tǒng)如果不搭配特殊的應(yīng)用軟件的話,是肯定不能夠顯示中文的。

    還有一個(gè)問(wèn)題,就是在 Java 編程過(guò)程中,對(duì)中文字符進(jìn)行正確的編碼轉(zhuǎn)換。例如,向網(wǎng)頁(yè)輸出中文字符串的時(shí)候,不論你是用

    out.println(string);還是用

    <%=string%>,都必須作 UNICODE GBK 的轉(zhuǎn)換,或者手動(dòng),或者自動(dòng)。在 JSP 1.0中,可以定義輸出字符集,從而實(shí)現(xiàn)內(nèi)碼的自動(dòng)轉(zhuǎn)換。用法是

    <%@page contentType=”text/html;charset=gb2312” %>

    但是在一些 JSP 版本中并沒(méi)有提供對(duì)輸出字符集的支持,(例如 JSP 0.92),這就需要手動(dòng)編碼輸出了,方法非常多。最常用的方法是

    String s1 = request.getParameter(“keyword”);

    String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”);

    getBytes 方法用于將中文字符以“ISO-8859-1”編碼方式轉(zhuǎn)化成字節(jié)數(shù)組,而“GBK 是目標(biāo)編碼方式。我們從以ISO-8859-1方式編碼的數(shù)據(jù)庫(kù)中讀出中文字符串 s1 ,經(jīng)過(guò)上述轉(zhuǎn)換過(guò)程,在支持 GBK 字符集的操作系統(tǒng)和應(yīng)用軟件中就能夠正確顯示中文字符串 s2

    Java 中文問(wèn)題的表層分析及處理

    背景 

    開(kāi)發(fā)環(huán)境 JDK1.15 Vcafe2.0 JPadPro 

    服務(wù)器端 NT IIS Sybase System JconnectJDBC 

    客戶端 IE5.0 Pwin98 ?span > 

    .CLASS 文件存放在服務(wù)器端,由客戶端的瀏覽器運(yùn)行 APPLET APPLET 只起調(diào)入 FRAME 類等主程序的作用。界面包括 Textfield TextAreaListChoice 等。

    I. JDBC 執(zhí)行 SELECT 語(yǔ)句從服務(wù)器端讀取數(shù)據(jù)(中文)后,將數(shù)據(jù)用 APPEND 方法加到 TextAreaTA ,不能正確顯示。但加到 List 中時(shí),大部分漢字卻可正確顯示。

    將數(shù)據(jù)按“ISO-8859-1 編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按系統(tǒng)缺省編碼方式 Default Character Encoding 轉(zhuǎn)化為 STRING ,即可在 TA List 中正確顯示。

    程序段如下:

    dbstr2 = results.getString(1);

    //After reading the result from DB serverconverting it to string.

    dbbyte1 = dbstr2.getBytes(“iso-8859-1”);

    dbstr1 = new String(dbbyte1);

    在轉(zhuǎn)換字符串時(shí)不采用系統(tǒng)默認(rèn)編碼方式,而直接采用“ GBK 或者 GB2312 , A B 兩種情況下,從數(shù)據(jù)庫(kù)取數(shù)據(jù)都沒(méi)有問(wèn)題。

    II.處理方式與“取中文”相逆,先將 SQL 語(yǔ)句按系統(tǒng)缺省編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按“ISO-8859-1”編碼方式轉(zhuǎn)化為 STRING ,最后送去執(zhí)行,則中文信息可正確寫(xiě)入數(shù)據(jù)庫(kù)。

    程序段如下:

    sqlstmt = tf_input.getText();

    //Before sending statement to DB serverconverting it to sql statement.

    dbbyte1 = sqlstmt.getBytes();

    sqlstmt = newString(dbbyte1,”iso-8859-1”);

    _stmt = _con.createStatement();

    _stmt.executeUpdate(sqlstmt);

    ……

    問(wèn)題:如果客戶機(jī)上存在 CLASSPATH 指向 JDK CLASSES.ZIP 時(shí)(稱為 A 情況),上述程序代碼可正確執(zhí)行。但是如果客戶機(jī)只有瀏覽器,而沒(méi)有 JDK CLASSPATH 時(shí)(稱為 B 情況),則漢字無(wú)法正確轉(zhuǎn)換。

    我們的分析:

    1.經(jīng)過(guò)測(cè)試,在 A 情況下,程序運(yùn)行時(shí)系統(tǒng)的缺省編碼方式為 GBK 或者 GB2312 。在 B 情況下,程序啟動(dòng)時(shí)瀏覽器的 JAVA 控制臺(tái)中出現(xiàn)如下錯(cuò)誤信息:

    Can't find resource for sun.awt.windows.awtLocalization_zh_CN

    然后系統(tǒng)的缺省編碼方式為“8859-1”。

    2.如果在轉(zhuǎn)換字符串時(shí)不采用系統(tǒng)缺省編碼方式,而是直接采用 GBK 或“GB2312”,則在 A 情況下程序仍然可正常運(yùn)行,在 B 情況下,系統(tǒng)出現(xiàn)錯(cuò)誤:

    UnsupportedEncodingException

    3.在客戶機(jī)上,把 JDK CLASSES.ZIP 解壓后,放在另一個(gè)目錄中, CLASSPATH 只包含該目錄。然后一邊逐步刪除該目錄中的 .CLASS 文件,另一邊運(yùn)行測(cè)試程序,最后發(fā)現(xiàn)在一千多個(gè) CLASS 文件中,只有一個(gè)是必不可少的,該文件是:

    sun.io.CharToByteDoubleByte.class

    將該文件拷到服務(wù)器端和其它的類放在一起,并在程序的開(kāi)頭 IMPORT 它,在 B 情況下程序仍然無(wú)法正常運(yùn)行。

    4. A 情況下,如果在 CLASSPTH 中去掉 sun.io.CharToByteDoubleByte.class ,則程序運(yùn)行時(shí)測(cè)得默認(rèn)編碼方式為“8859-1”,否則為 GBK GB2312

    如果 JDK 的版本為1.2以上的話,在 B 情況下遇到的問(wèn)題得到了很好的解決,測(cè)試的步驟同上,有興趣的讀者可以嘗試一下。

    Java 中文問(wèn)題的根源分析及解決

    在簡(jiǎn)體中文 MS Windows 98 + JDK 1.3 下,可以用 System.getProperties() 得到 Java 運(yùn)行環(huán)境的一些基本屬性,類 PoorChinese 可以幫助我們得到這些屬性。

    PoorChinese 的源代碼:

    public class PoorChinese {

    }

    執(zhí)行 java PoorChinese 后,我們會(huì)得到:

    系統(tǒng)變量 file.encoding 的值為 GBK user.language 的值為 zh user.region 的值為 CN ,這些系統(tǒng)變量的值決定了系統(tǒng)默認(rèn)的編碼方式是 GBK

    在上述系統(tǒng)中,下面的代碼將 GB2312 文件轉(zhuǎn)換成 Big5 文件,它們能夠幫助我們理解 Java 中漢字編碼的轉(zhuǎn)化:

    ?

    import java.io.*;

    import java.util.*;

    ?

    public class gb2big5 {

    ?

    static int iCharNum=0;

    ?

    public static void main(String[] args) {

    System.out.println("Input GB2312 file, output Big5 file.");

    if (args.length!=2) {

    System.err.println("Usage: jview gb2big5 gbfile big5file");

    System.exit(1);

    String inputString = readInput(args[0]);

    writeOutput(inputString,args[1]);

    System.out.println("Number of Characters in file: "+iCharNum+".");

    }

    ?

    static void writeOutput(String str, String strOutFile) {

    try {

    FileOutputStream fos = new FileOutputStream(strOutFile);

    Writer out = new OutputStreamWriter(fos, "Big5");

    out.write(str);

    out.close();

    }

    catch (IOException e) {

    e.printStackTrace();

    e.printStackTrace();

    }

    }

    ?

    static String readInput(String strInFile) {

    StringBuffer buffer = new StringBuffer();

    try {

    FileInputStream fis = new FileInputStream(strInFile);

    InputStreamReader isr = new InputStreamReader(fis, "GB2312");

    Reader in = new BufferedReader(isr);

    int ch;

    while ((ch = in.read()) > -1) {

    iCharNum += 1;

    buffer.append((char)ch);

    }

    in.close();

    return buffer.toString();

    }

    catch (IOException e) {

    e.printStackTrace();

    return null;

    }

    }

    }

    ?

                          

    編碼轉(zhuǎn)化的過(guò)程如下:

    GB2312------------------>Unicode------------->Big5

    執(zhí)行 java gb2big5 gb.txt big5.txt ,如果 gb.txt 的內(nèi)容是“今天星期三”,則得到的文件 big5.txt 中的字符能夠正確顯示;而如果 gb.txt 的內(nèi)容是“情人節(jié)快樂(lè)”,則得到的文件 big5.txt 中對(duì)應(yīng)于“節(jié)”和“樂(lè)”的字符都是符號(hào)“?”(0x3F),可見(jiàn) sun.io.ByteToCharGB2312 sun.io.CharToByteBig5 這兩個(gè)基本類并沒(méi)有編好。

    正如上例一樣, 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 ,在返回前將 sbStringBuffer 復(fù)制成 byte bs[] ,然后 return new String(bs,GB2312)。作上述修改后就需要自己解碼了:

    HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者

    form=HttpUtils.parsePostData(……)

    千萬(wàn)別忘了編譯后放到 Servlet.jar 里面。

    關(guān)于 Java 中文問(wèn)題的總結(jié)

    Java 編程語(yǔ)言成長(zhǎng)于網(wǎng)絡(luò)世界,這就要求 Java 對(duì)多國(guó)字符有很好的支持。 Java 編程語(yǔ)言適應(yīng)了計(jì)算的網(wǎng)絡(luò)化的需求,為它能夠在網(wǎng)絡(luò)世界迅速成長(zhǎng)奠定了堅(jiān)實(shí)的基礎(chǔ)。 Java 的締造者 Java Soft 已經(jīng)考慮到 Java 編程語(yǔ)言對(duì)多國(guó)字符的支持,只是現(xiàn)在的解決方案有很多缺陷在里面,需要我們付諸一些補(bǔ)償性的措施。而世界標(biāo)準(zhǔn)化組織也在努力把人類所有的文字統(tǒng)一在一種編碼之中,其中一種方案是 ISO10646 ,它用四個(gè)字節(jié)來(lái)表示一個(gè)字符。當(dāng)然,在這種方案未被采用之前,還是希望 Java Soft 能夠嚴(yán)格地測(cè)試它的產(chǎn)品,為用戶帶來(lái)更多的方便。

    附一個(gè)用于從數(shù)據(jù)庫(kù)和網(wǎng)絡(luò)中取出 中文亂碼的處理函數(shù),入?yún)⑹怯袉?wèn)題的字符串,出參是問(wèn)題已經(jīng)解決了的字符串。

    技術(shù)應(yīng)用者提供解決方案

    關(guān)于作者

     段明輝 has co-authored this article

    編譯代碼文件,要用

             javac -encoding GBK   xxxxxx.java

       如果是用ant工具,

           <target name="compile" depends="prepare" description="complie All Java source">
              <copy todir="${build.dir}">
                <fileset dir="${src.dir}" includes="**/*.properties" />
             </copy>
             <javac srcdir="${src.dir}" destdir="${build.dir}" encoding="GBK">
                <classpath refid="project.classpath" />
             </javac>

          </target>

    posted on 2007-09-03 15:49 哼哼 閱讀(353) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA-Common
    主站蜘蛛池模板: 午夜国产精品免费观看| 久久精品成人免费网站| 51午夜精品免费视频| 国产免费久久精品99久久| 日本免费中文字幕| 18国产精品白浆在线观看免费| 最近的免费中文字幕视频| 国产不卡免费视频| 亚洲av最新在线网址| 久久精品亚洲AV久久久无码| 国产亚洲午夜精品| 久久久高清日本道免费观看| 四虎永久在线观看免费网站网址| 国产高清在线免费| 亚洲精品国精品久久99热一| 亚洲经典在线中文字幕| 色噜噜噜噜亚洲第一| 拍拍拍无挡视频免费观看1000 | 午夜免费国产体验区免费的| 成人黄网站片免费视频| 国产成人无码免费看视频软件| 免费成人av电影| 久久精品国产亚洲AV无码偷窥| 亚洲国产精华液2020| 伊人免费在线观看| 日韩亚洲国产高清免费视频| 亚洲精品国产综合久久一线| 亚洲视频在线观看一区| 国产亚洲一卡2卡3卡4卡新区 | 久久久青草青青亚洲国产免观| 亚洲午夜在线播放| 精品久久久久久无码免费| 青娱乐免费在线视频| 国产精品亚洲产品一区二区三区| 亚洲国产亚洲片在线观看播放| 免费人成动漫在线播放r18| a拍拍男女免费看全片| 亚洲一级片免费看| 亚洲资源最新版在线观看| 99视频在线观看免费| 午夜视频在线观看免费完整版|