Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » 移动互联网  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 [转贴]J2ME之中文处理
4bug





发贴: 26
积分: 0
于 2004-05-09 01:30 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
作者:微型爪哇人 July
2003台灣在Java手機程式的訓練及開發上還屬於啟蒙階段,目前國內電信業者所引進的Java手機軟體大多由日本或歐美國家所開發,鮮少專門針對國人所設計的軟體,不過最近看到有不少遊戲或軟體開發公司積極投入Java手機軟體的研發,也有許多的學生及老師開始以J2ME技術為實做專題,相信即將看到有越來越多的Java手機軟體是由我們所自行研發。不過要講本土化就不得不談文字問題了,中文的處理對有些Java新手而言真的是非常的頭痛,不管這些中文字是從JSP網頁來或是放在檔案內,每次遇到顯示中文時就會出現一堆亂碼。其實Java對文字的支援可是非常廣泛的,能不能被正確使用端看你對文字處理的觀念清不清楚,本篇文章就來和大家談一談中文的處理方式。我們在電腦螢幕上看的的文字,不論是中文、英文或數字等,在內部都有一個代碼來表示,作業系統可以依據這些代碼來處理文字,或是到字型庫內找到文字的影像。制定代碼的方式是透過編碼規則來決定,同一個字在不同的編碼規則下所定義的代碼可能不相同,作業系統可以同時支援多種編碼規則,因此在進行文字處理時作業系統必須要知道是依據何種編碼規則來進行。例如同樣一個中文字”大”,使用廣泛用於中國大陸及採用簡體字的地區GB碼和適用於台灣、香港,及採用繁體字的地區的BIG5碼所編定的內碼就不一樣。一般人最熟悉的編碼方式就是ASCII了,由於早期的電腦系統是發源於美國,因此最早的編碼系統也是發源於此。

英文系統的資料只需數字、26 個英文字母 (包括大小寫)、標點與其他特殊符號、外加一些控制碼即可,因此當時一個位元組的大小只需 7 個位元即可包含所有所需的資訊,總共可容納 128 個符號。後來又考慮到歐洲的需求(例如拉丁文字),再把編碼長度擴大到8位元,這就成了ISO8859 的編碼標準。
不過要對亞洲的文字做編碼可就複雜多了,由於資訊交換的需要,為了將世界上的所有主流文字能用一種標準的編碼方式表示,由一個名為 Unicode Consortium的機構制訂了國際化的文字編碼系統unicode。Unicode是採用16 bit之編碼方式,亦即每一個字都佔了兩個位元組大小,而且對ASCII有向前的相容性。Java語言在構思的時候就將文字的國際化考慮進去了,因此Java語言內代表文字的基本資料型態char的大小就是兩個位元組,並以unicode編碼來表示文字。來看一下下面這段簡單的程式碼:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class I18NTest extends MIDlet{
Display display;
Form form;
public I18NTest(){
form = new Form("標題");
display = Display.getDisplay(this);
}
public void startApp(){
display.setCurrent(form);
form.append("這裡是內容");
}
public void pauseApp(){}
public void destroyApp(boolean unconditional){}
}

如果我們利用反編譯程式可以還原成為

import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
public class I18NTest extends MIDlet{
public I18NTest(){
form = new Form("\u6A19\u984C");
display = Display.getDisplay(this);
}
public void startApp(){
display.setCurrent(form);
form.append("\u9019\u88E1\u662F\u5167\u5BB9");
}
public void pauseApp(){}
public void destroyApp(boolean flag){}
Display display;
Form form;
}

我們可以清楚看到文字”這裡是內容"實際上在Java內是以unicode的\u9019\u88E1\u662F\u5167\u5BB9表示。
因為Java是以unicode編碼的方式表示文字,所以不論程式要處理的文字來源是哪裡,請記住一定知道來源資料的編碼方式,然後將其轉換成unicode之後才能正確顯示或處理。

先看第一種情況,文字的資料來自包在JAR檔內的文字檔。假設我在一個名為test.txt的文字內寫這些文字”GO!J2MER!”,下面是一般初學者處理的方式:

String content = "";
int ch;
try{
InputStream in = getClass().getResourceAsStream("test.txt");
while((ch = in.read()) != -1){
System.out.println("" + ch);
content += (char)ch;
}
}catch(Exception ex){}

結果這段程式碼正確顯示文字,現在我們改放”中文顯示”在test.txt內,再執行一次看看結果,結果竟然出現了可怕的亂碼,這是怎麼一回事呢?
原因在於原來的文字編碼沒有正確的轉換成unicode。先來看看test.txt的編碼方式,我使用的是中文Windows作業系統,其預設的編碼方式是MS950,所以你在test.txt文字檔寫的內容都會經過MS950編碼。MS950相容於BIG5編碼,英文字和基本符號會以一個位元組表示,而中文則會用兩個以上的位元組表示。

再來看看InputStream類別的read()方法,這個方法一次會讀取一個位元組,而在程式碼中的處理方式是每讀取一個位元組就轉成char型態當作一個字元,這樣的做法在英文中是行的通的,然而一個中文字是以兩個以上的位元組組成,如果把這兩個位元組拆開來將其視為獨立的兩個字就會出現亂碼。因此我們應該要做的就是將MS950編碼過後的文字轉成unicode。
不過可惜的是,因為手機儲存空間的限制,不可能將所有可能的編碼方式都內建在手機內,大部分的Java手機都支援UTF8編碼,因此可以用一個間接的做法,把原先的編碼方式先轉成UTF8編碼,然後在程式中將UTF8轉成unicode。
J2SDK提供一個工具叫native2ascii可以用來做這件事。native2ascii工具可以將來源檔案的內容轉換成Java的unicode形式test_unicode.txt:
   native2ascii test.txt test_unicode.txt 

接著再次利用native2ascii工具將unicode形式的test_unicode.txt轉換成UTF8編碼test.txt:
 native2ascii -reverse -encoding utf8 test_unicode.txt test.txt

現在原來在test.txt的中文內容已經用UTF8重新編碼過了,現在你可以在MIDlet中將test.txt利用UTF8讀出:

String content = "";
char[] myData = new char[100];
try{
InputStream in = getClass().getResourceAsStream("test.txt"); /* 將test.txt的內容依UTF8的編碼轉回unicode */
InputStreamReader din = new InputStreamReader(in, "UTF-8");
din.read(myData, 0, myData.length);
content = new String(myData); /* content就是正確的中文字串 */
din.close();
} catch(tException ex){}

或是用

String content = "";
char[] myData = new char[100]; /* 要確定這個大小是足夠的 */
try{
InputStream in = getClass().getResourceAsStream("test.txt");
DataInputStream din = new DataInputStream(in);
dis.read(myData); /* 將test.txt的內容依UTF8的編碼轉回unicode */
content = new String(myData, "UTF-8"); //content就是正確的中文字串
dis.close();
} catch(tException ex){}

結果可以看出,我們正確的將中文字顯示出來了: 要正確處理JAD內的中文內容也可以這麼做,因為大部分的Java手機也是以UTF8的方式將JAD檔讀入處理。例如我們希望表示MIDlet名稱的屬性MIDlet-1以中文命名,一樣用native2ascii工具轉成UTF8編碼,結果MIDlet名稱果然能夠正確的顯示: 一樣的道理讓我們來看看另一個讓人困惑的地方-JSP和servlet。JSP網頁在撰寫完成後,作業系統會以預設的編碼方式儲存JSP檔案,如果想要在MIDlet中直接處理包含中文的JSP網頁,依然會出現亂碼。
要正確處理JSP網頁有兩個步驟,第一個步驟應該大家都知道,要把page指令的contentType屬性設為text/html; charset=Big5:這個動作背後有兩個涵義,第一個涵義是告訴Java編譯器JSP的原始檔是以Big5的編碼方式(事實上是MS950)儲存,Java編譯器在編譯時才能正確的轉換中文內容為unicode。
第二個涵義是當MIDlet(或一般的瀏覽器)要存取這個JSP網頁時,JSP container會再把unicode轉成Big5編碼的方式輸出。所以現在我們應該修正的就是後面這個步驟,讓JSP container把JSP改以UTF8編碼輸出,你可以在JSP網頁內加入:response.setCharacterEncoding(UTF-8)或response.setContentType(text/html;charset=UTF-8)這個動作就會讓讓JSP container把JSP改以UTF8編碼輸出了,接下來你只要在收到輸入資料流之後,依上面我們處理test.txt的方式處理即可(不過我一直認為MIDlet不應該直接處理JSP)。
Servlet的情況是類似的,不過如果你要在Servlet內使用資料串流的方式送出中文資料,你可以使用DataOutputStream類別的writeUTF()方法,然後MIDlet直接以DataInputStream類別的readUTF()方法取得中文內容即可。中文的處理是常常會碰到的問題,不過其實並不難,你只要知道所有字在不同的系統中會以不同的代碼表示以及Java以unicode編碼就可以了,剩下的就是想辦法把原來的編碼轉成unicode的形式,希望閱讀完這篇文章,大家從此就喜歡寫中文的MIDlet了。如果您對這篇文章有任何意見,可以寫信到midletcreator@yahoo.com.tw給我。




flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923