|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
从一个编程语言的普及程度来将,一个好的IDE是至关中要的,而现在的java的IDE虽然已经很好了,但是和.net比起来还是稍微差一些的,这是个客观事实。java要想普及的更好。DE是必须加以改进的。编程|汉字|办理|成绩Java编程手艺中汉字成绩的剖析及办理
段明辉
自在撰稿人
2000年11月8日
在基于Java言语的编程中,我们常常碰着汉字的处置及显现的成绩。一年夜堆看不懂的乱码一定不是我们乐意看到的显现效果,如何才干够让那些汉字准确显现呢?Java言语默许的编码体例是UNICODE,而我们中国人一般利用的文件和数据库都是基于GB2312大概BIG5等体例编码的,如何才干够得当地选择汉字编码体例并准确地处置汉字的编码呢?本文将从汉字编码的知识动手,分离Java编程实例,剖析以上两个成绩并提出办理它们的计划。
如今Java编程言语已普遍使用于互联网天下,早在Sun公司开辟Java言语的时分,就已思索到对非英笔墨符的撑持了。Sun公司发布的Java运转情况(JRE)自己就分英文版和国际版,但只要国际版才撑持非英笔墨符。不外在Java编程言语的使用中,对中笔墨符的撑持并不是好像JavaSoft的尺度标准中所传播鼓吹的那样完善,由于中笔墨符集不但一个,并且分歧的操纵体系对中笔墨符的撑持也不尽不异,以是会有很多和汉字编码处置有关的成绩在我们举行使用开辟中困扰着我们。有良多关于这些成绩的解答,但都对照噜苏,其实不可以满意人人急切办理成绩的希望,关于Java中文成绩的体系研讨其实不多,本文从汉字编码知识动身,剖析Java中文成绩,但愿对人人办理这个成绩有所匡助。
汉字编码的知识
我们晓得,英笔墨符通常为以一个字节来暗示的,最经常使用的编码办法是ASCII。但一个字节最多只能辨别256个字符,而汉字不计其数,以是如今都以双字节来暗示汉字,为了可以与英笔墨符分隔,每一个字节的最高位必定为1,如许双字节最多能够暗示64K格字符。我们常常碰着的编码体例有GB2312、BIG5、UNICODE等。关于详细编码体例的具体材料,有乐趣的读者能够查阅相干材料。我浅薄谈一下和我们干系亲切的GB2312和UNICODE。GB2312码,中华国民共和国国度尺度汉字信息互换用编码,是一个由中华国民共和国国度尺度总局公布的关于简化汉字的编码,通行于中国年夜海洋区及新加坡,简称国标码。两个字节中,第一个字节(高字节)的值为区号值加32(20H),第二个字节(低字节)的值为位号值加32(20H),用这两个值来暗示一个汉字的编码。UNICODE码是微软提出的办理多国字符成绩的多字节等长编码,它对英笔墨符接纳后面加“0”字节的战略完成等长兼容。如“A”的ASCII码为0x41,UNICODE就为0x00,0x41。使用特别的工具各类编码之间能够相互转换。
Java中文成绩的开端熟悉
我们基于Java编程言语举行使用开辟时,不成制止地要处置中文。Java编程言语默许的编码体例是UNICODE,而我们一般利用的数据库及文件都是基于GB2312编码的,我们常常碰着如许的情形:扫瞄基于JSP手艺的网站看到的是乱码,文件翻开后看到的也是乱码,被Java修正过的数据库的内容在其余场所使用时没法持续准确地供应信息。
StringsEnglish=“apple”;
StringsChinese=“苹果”;
Strings=“苹果apple”;
sEnglish的长度是5,sChinese的长度是4,而s默许的长度是14。关于sEnglish来讲,Java中的各个类都撑持得十分好,一定可以准确显现。但关于sChinese和s来讲,固然JavaSoft声明Java的基础类已思索到对多国字符的撑持(默许UNICODE编码),可是假如操纵体系的默许编码不是UNICODE,而是国标码等。从Java源代码到失掉准确的了局,要经由“Java源代码->Java字节码->;假造机->操纵体系->显现设备”的历程。在上述过程当中的每步骤,我们都必需准确地处置汉字的编码,才干够使终极的显现了局准确。
“Java源代码->Java字节码”,尺度的Java编译器javac利用的字符集是体系默许的字符集,好比在中文Windows操纵体系上就是GBK,而在Linux操纵体系上就是ISO-8859-1,以是人人会发明在Linux操纵体系上编译的类中源文件中的中笔墨符都出了成绩,办理的举措就是在编译的时分增加encoding参数,如许才干够与平台有关。用法是
javacCencodingGBK。
“Java字节码->假造机->操纵体系”,Java运转情况(JRE)分英文版和国际版,但只要国际版才撑持非英笔墨符。Java开辟工具包(JDK)一定撑持多国字符,但并不是一切的盘算机用户都安装了JDK。良多操纵体系及使用软件为了可以更好的撑持Java,都内嵌了JRE的国际版本,为本人撑持多国字符供应了便利。
“操纵体系->显现设备”,关于汉字来讲,操纵体系必需撑持并可以显现它。英文操纵体系假如不搭配特别的使用软件的话,是一定不克不及够显现中文的。
另有一个成绩,就是在Java编程过程当中,对中笔墨符举行准确的编码转换。比方,向网页输入中笔墨符串的时分,不管你是用
out.println(string);//string是含中文的字符串
仍是用
<%=string%>,都必需作UNICODE到GBK的转换,大概手动,大概主动。在JSP1.0中,能够界说输入字符集,从而完成内码的主动转换。用法是
<%@pageContentType=”text/html;charset=gb2312”%>
可是在一些JSP版本中并没有供应对输入字符集的撑持,(比方JSP0.92),这就必要手动编码输入了,办法十分多。最经常使用的办法是
Strings1=request.getParameter(“keyword”);
Strings2=newString(s1.getBytes(“ISO-8859-1”),”GBK”);
getBytes办法用于将中笔墨符以“ISO-8859-1”编码体例转化成字节数组,而“GBK”是方针编码体例。我们从以ISO-8859-1体例编码的数据库中读出中笔墨符串s1,经由上述转换历程,在撑持GBK字符集的操纵体系和使用软件中就可以够准确显现中笔墨符串s2。
Java中文成绩的表层剖析及处置
背景
开辟情况
JDK1.15
Vcafe2.0
JPadPro
服务器端
NTIIS
SybaseSystem
Jconnect(JDBC)
客户端
IE5.0
Pwin98
.CLASS文件寄存在服务器端,由客户真个扫瞄器运转APPLET,APPLET只起调进FRAME类等主程序的感化。界面包含Textfield,TextArea,List,Choice等。
I.取中文
用JDBC实行SELECT语句从服务器端读取数据(中文)后,将数据用APPEND办法加到TextArea(TA),不克不及准确显现。但加到List中时,年夜部分汉字却可准确显现。
将数据按“ISO-8859-1”编码体例转化为字节数组,再按体系缺省编码体例(DefaultCharacterEncoding)转化为STRING,便可在TA和List中准确显现。
程序段以下:
dbstr2=results.getString(1);
//AfterreadingtheresultfromDBserver,convertingittostring.
dbbyte1=dbstr2.getBytes(“iso-8859-1”);
dbstr1=newString(dbbyte1);
在转换字符串时不接纳体系默许编码体例,而间接接纳“GBK”大概“GB2312”,在A和B两种情形下,从数据库取数据都没有成绩。
II.写中文到数据库
处置体例与“取中文”相逆,先将SQL语句按体系缺省编码体例转化为字节数组,再按“ISO-8859-1”编码体例转化为STRING,最初送往实行,则中文信息可准确写进数据库。
程序段以下:
sqlstmt=tf_input.getText();
//BeforesendingstatementtoDBserver,convertingittosqlstatement.
dbbyte1=sqlstmt.getBytes();
sqlstmt=newString(dbbyte1,”iso-8859-1”);
_stmt=_con.createStatement();
_stmt.executeUpdate(sqlstmt);
……
成绩:假如客户机上存在CLASSPATH指向JDK的CLASSES.ZIP时(称为A情形),上述程序代码可准确实行。可是假如客户机只要扫瞄器,而没有JDK和CLASSPATH时(称为B情形),则汉字没法准确转换。
我们的剖析:
1.经由测试,在A情形下,程序运转时体系的缺省编码体例为GBK大概GB2312。在B情形下,程序启动时扫瞄器的JAVA把持台中呈现以下毛病信息:
Cantfindresourceforsun.awt.windows.awtLocalization_zh_CN
然后体系的缺省编码体例为“8859-1”。
2.假如在转换字符串时不接纳体系缺省编码体例,而是间接接纳“GBK”或“GB2312”,则在A情形下程序仍旧可一般运转,在B情形下,体系呈现毛病:
UnsupportedEncodingException。
3.在客户机上,把JDK的CLASSES.ZIP解压后,放在另外一个目次中,CLASSPATH只包括该目次。然后一边慢慢删除该目次中的.CLASS文件,另外一边运转测试程序,最初发明在一千多个CLASS文件中,只要一个是必不成少的,该文件是:
sun.io.CharToByteDoubleByte.class。
将该文件拷到服务器端和别的的类放在一同,并在程序的开首IMPORT它,在B情形下程序仍旧没法一般运转。
4.在A情形下,假如在CLASSPTH中往失落sun.io.CharToByteDoubleByte.class,则程序运转时测得默许编码体例为“8859-1”,不然为“GBK”或“GB2312”。
假如JDK的版本为1.2以上的话,在B情形下碰到的成绩失掉了很好的办理,测试的步骤同上,有乐趣的读者能够实验一下。
Java中文成绩的本源剖析及办理
在简体中文MSWindows98+JDK1.3下,能够用System.getProperties()失掉Java运转情况的一些基础属性,类PoorChinese能够匡助我们失掉这些属性。
类PoorChinese的源代码:
publicclassPoorChinese{
publicstaticvoidmain(String[]args){
System.getProperties().list(System.out);
}
}
实行javaPoorChinese后,我们会失掉:
体系变量file.encoding的值为GBK,user.language的值为zh,user.region的值为CN,这些体系变量的值决意了体系默许的编码体例是GBK。
在上述体系中,上面的代码将GB2312文件转换成Big5文件,它们可以匡助我们了解Java中汉字编码的转化:
importjava.io.*;
importjava.util.*;
publicclassgb2big5{
staticintiCharNum=0;
publicstaticvoidmain(String[]args){
System.out.println("InputGB2312file,outputBig5file.");
if(args.length!=2){
System.err.println("Usage:jviewgb2big5gbfilebig5file");
System.exit(1);
}
StringinputString=readInput(args[0]);
writeOutput(inputString,args[1]);
System.out.println("NumberofCharactersinfile:"+iCharNum+".");
}
staticvoidwriteOutput(Stringstr,StringstrOutFile){
try{
FileOutputStreamfos=newFileOutputStream(strOutFile);
Writerout=newOutputStreamWriter(fos,"Big5");
out.write(str);
out.close();
}
catch(IOExceptione){
e.printStackTrace();
e.printStackTrace();
}
}
staticStringreadInput(StringstrInFile){
StringBufferbuffer=newStringBuffer();
try{
FileInputStreamfis=newFileInputStream(strInFile);
InputStreamReaderisr=newInputStreamReader(fis,"GB2312");
Readerin=newBufferedReader(isr);
intch;
while((ch=in.read())>-1){
iCharNum+=1;
buffer.append((char)ch);
}
in.close();
returnbuffer.toString();
}
catch(IOExceptione){
e.printStackTrace();
returnnull;
}
}
}
编码转化的历程以下:
ByteToCharGB2312CharToByteBig5
GB2312------------------>Unicode------------->Big5
实行javagb2big5gb.txtbig5.txt,假如gb.txt的内容是“明天礼拜三”,则失掉的文件big5.txt中的字符可以准确显现;而假如gb.txt的内容是“恋人节康乐”,则失掉的文件big5.txt中对应于“节”和“乐”的字符都是标记“?”(0x3F),可见sun.io.ByteToCharGB2312和sun.io.CharToByteBig5这两个基础类并没有编好。
正如上例一样,Java的基础类也大概存在成绩。因为国际化的事情并非在国际完成的,以是在这些基础类公布之前,没有经由严厉的测试,以是对中笔墨符的撑持其实不像JavaSoft所宣称的那样完善。前不久,我的一名手艺上的伴侣发信给我说,他终究找到了JavaServlet中文成绩的本源。两周以来,他一向为JavaServlet的中文成绩所困扰,由于每面临一个含有中笔墨符的字符串都必需举行强迫转换才干够失掉准确的了局(这好象是人人公认的独一的办理举措)。厥后,他的确不想云云持续循分下往了,由于如许的事变的确不该该是初级程序员所要做的事情,他就找出Servlet解码的源代码举行剖析,由于他嫌疑成绩就出在解码这部分。经由四个小时的搏斗,他终究找到了成绩的本源地点。本来他的嫌疑是准确的,Servlet的解码部分完整没有思索双字节,间接把%XX看成一个字符。(本来JavaSoft也会犯这幺初级的毛病!)
假如你对这个成绩有乐趣大概碰到了一样的懊恼的话,你能够依照他的步骤对Servlet.jar举行修正:
找到源代码HttpUtils中的staticprivateStringparseName,在前往前将sb(StringBuffer)复制成bytebs[],然后returnnewString(bs,”GB2312”)。作上述修正后就必要本人解码了:
HashTableform=HttpUtils.parseQueryString(request.getQueryString())大概
form=HttpUtils.parsePostData(……)
万万别忘了编译后放到Servlet.jar内里。
5、关于Java中文成绩的总结
Java编程言语发展于收集天下,这就请求Java对多国字符有很好的撑持。Java编程言语顺应了盘算的收集化的需求,为它可以在收集天下敏捷发展奠基了坚固的基本。Java的创作发明者(JavaSoft)已思索到Java编程言语对多国字符的撑持,只是如今的办理计划有良多缺点在内里,必要我们付诸一些抵偿性的措施。而天下尺度化构造也在勉力把人类一切的笔墨一致在一种编码当中,个中一种计划是ISO10646,它用四个字节来暗示一个字符。固然,在这类计划未被接纳之前,仍是但愿JavaSoft可以严厉地测试它的产物,为用户带来更多的便利。
附一个用于从数据库和收集中掏出中文乱码的处置函数,进参是有成绩的字符串,出参是成绩已办理了的字符串。
StringparseChinese(Stringin)
{
Strings=null;
bytetemp[];
if(in==null)
{
System.out.println("Warn:Chinesenullfounded!");
returnnewString("");
}
try
{
temp=in.getBytes("iso-8859-1");
temp=in.getBytes("iso-8859-1");
s=newString(temp);
}
{
System.out.println("Warn:Chinesenullfounded!");
returnnewString("");
}
try
{
temp=in.getBytes("iso-8859-1");
s=newString(temp);
}
catch(UnsupportedEncodingExceptione)
{
System.out.println(e.toString());
}
returns;
}
作者简介
段明辉,清华年夜学电子工程系先生
如今正在清华年夜学微电子学研讨所处置Java智能卡微处置器的研讨和开辟
向导BBS水木清华站的Java会商组,为浩瀚Java手艺使用者供应办理计划
有了这样一个呼声:让java代替C语言成为基本语言。这些足以说明java简单易学的这个优点。其次,java的功能强大,前面我也提到了,EJB3.0的推出使java成为了大型项目的首选。 |
|