在基于Java语言的编程中,我们经常遇到汉字的处理和显示问题。很多看不懂的东西 乱码绝对不是我们愿意看到的显示效果,那些汉字怎么能正确显示呢?Java语言 UNICODE是默认的编码方法,我们中国人通常使用基于GB2312的文件和数据库 或者BIG5等编码方式,如何正确选择汉字编码方式,正确处理汉字编码? 码呢?本文将从汉字编码的常识入手,结合Java编程的实例,分析上述两个问题并提出 解决它们的方案。
---- 现在Java编程语言已经广泛应用于互联网世界,早在Sun开发Java语言时 ,考虑到对非英文字符的支持。Sun公司公布的Java运行环境(JRE)本身就 分为英文版和国际版,但只有国际版才支持非英文字符。但在Java编程语言的应用中 ,对中文字符的支持并不像JavaSoft的标准规范所说的那么完美,因为中文字符 不止一个符集,不同的操作系统对中文字符有不同的支持,所以会有很多和汉 在我们的应用开发中,字编码处理相关问题困扰着我们。有很多关于这些问题的答案 ,但都是琐碎的,不能满足大家解决问题的迫切愿望。关于Java中文问题的系统 研究不多。本文从汉字编码常识出发,分析了Java的中文问题,希望能解决这个问题 问题有帮助。 汉字编码常识 众所周知,英文字符通常用一个字节来表示,最常用的编码方法是ASCII。但一个 字节最多只能区分256个字符,而汉字数千个,所以现在都是用双字节来表示汉字,为了 它可以与英文字符分开,每个字节的最高水平必须是1,这样双字节最多可以表示64K格子字符 。
GB2312是我们经常遇到的编码方法、BIG5、UNICODE等。关于具体编码方法的详细资料 有兴趣的读者可以查阅相关资料。让我肤浅地谈谈GB2312和UNI,它与我们密切相关 CODE。GB2312码是中华人民共和国国家标准汉字信息交换的编码。 在中国大陆和新加坡,简称国家标准总局发布的关于简化汉字的编码 标码。在两个字节中,第一个字节(高字节)的值为区号值加32(20H),第二个字节(低字节) 字节)的值为位数值加32(20H),用这两个值表示一个汉字的编码。UNICODE代码为微 软提出的解决多国字符问题的多字节等长编码,对英文字符采取前加“0”字节的策略 稍微实现等长兼容。如“AASCII码为0x41,UNICODE为0x0,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操作系统中,它是GBK ISO-8859-1,所以你会发现在Linux操作系统上编译的类中源文件中的中文字符都出来了 了问题,解决办法是在编译过程中添加encoding参数,以便与平台无关。 用法是 javac–encodingGBK。 用法是 javac–encodingGBK。
“Java字节码->虚拟机->Java运行环境操作系统(JRE)分为英文版和国际版, 但只有国际版支持非英文字符。Java开发工具包(JDK)必须支持多国字符,但是 安装JDK的计算机用户并非所有。为了更好地支持Ja,许多操作系统和应用软件 va,JRE的国际版本都是嵌入式的,为自己支持多国字符提供了便利。 “操作系统->对汉字而言,操作系统必须支持并能够显示显示设备。英文操作 如果系统不配备特殊的应用软件,就不能显示中文。 另一个问题是在Java编程过程中正确编码和转换中文字符。例如,向 当网页输出中文字符串时,无论你使用它们 out.println(string);///string是中文字符串 还是用 <%=string%>,UNICODE必须转换为GBK,或手动或自动。JSP1.0中 ,输出字符集可以定义,从而实现内码的自动转换。用法是 <%@page ContentType=”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调入FR AME等主程序的作用。界面包括Textfield,TextArea,List,Choice等。界面包括Textfield,TextArea,List,Choice等。 I.取中文 使用JDBC执行SELECT语句从服务器端读取数据(中文)后,使用APPEND方法添加数据 到Textarea(TA),无法正确显示。但是当添加到List中时,大多数汉字都可以正确显示。 将数据按“ISO-8859-1“编码模式转换为字节数组,然后根据系统缺乏编码模式(Defaul tCharacterEncoding)将STRING转化为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情况),汉字不能正确转换。但如果客户机只有浏览器,而没有JDK和CLASSPATH, (称为B情况),汉字不能正确转换。
分析:
1.测试后,在A的情况下,GBK或GB2312是程序运行中系统缺少的编码方法。在 在B情况下,浏览器JAVA控制台在程序启动时出现以下错误信息: Can'tfindresourceforsun.awt.windows.awtLocalization_zh_CN 然后系统的缺失编码方法是“8859-1”。
2.如果在转换字符串时没有使用系统缺乏编码,而是直接使用“GBK或“GB2312” ,程序在A的情况下仍能正常运行,在B的情况下,系统出现错误: UnsupportedEncodingException。
3.将JDKCLASSES放在客户机上.ZIP解压后,放在另一个目录中,CLASPATH只包 含该目录。然后逐步删除目录中的目录.CLASS文件,另一边运行测试程序,最后发送 目前1000多个CLASS文件中,只有一个是必不可少的,文件是: sun.io.CharToByteDoubleByte.class。 将该文件复制到服务器端和其他类别,并在程序开始时IMPORT 程序仍然不能正常运行。
4.在A的情况下,如果在CLASPTH中去除sunn.io.CharToByteDoubleByte.class,则 默认编码模式为“8859-1”,否则为“8859-1”GBK或“GB2312”。 如果JDK的版本超过1.2,B情况下遇到的问题得到了很好的解决,测试的步骤 有兴趣的读者可以尝试一下。 [/b]分析和解决Java中文问题的根源[/b] MSWindows98+JDK1.3下,System可以使用.getProperties()得到Ja 类PorChinese可以帮助我们获得va运行环境的一些基本属性。 类PoorChinese的源代码: publicclassPoorChinese{ publicstaticvoidmain(String[]args){ System.getProperties().list(System.out); } } JavaPorChinese执行后,我们会得到: 系统变量file.GBK值Encoding,user.language的值为zh,user.region 这些系统变量的值是CN,这决定了GBK的默认编码方法。 下面的代码将GB2312文件转换为Big5文件,它们能帮助我们理解它们能帮助我们理解它们 Java汉字编码转换: importjava.io.*; importjava.util.*; publicclasgbbig5{ staticintiCharNum=0; publicstaticvoidmain(String[]args){ System.out.println(InputGB2312file,outputbig5file."); if(args.length!=2){ System.err.println("Usage:jviewgb2big5gbfilebigfile"); 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 javagb2big5gbbig执行.txtbig5.txt,如果gb.txt的内容是“今天星期三” 到达的文件big5.txt中的字符可以正确显示;如果gb.txt的内容是“情人节快乐” ,则得到达的文件big5.与“节”和“乐”相对应的txt字符是符号吗?"(0x3F), 可见sun.io.BytetocharGB2312.io.ChartobyteBig5这两个基本类别还没有编好 。(0x3F), 可见sun.io.BytetocharGB2312.io.CharToByteBig5这两个基本类别还没有编好。 。 就像上一个例子一样,Java的基本类也可能有问题。因为国际工作在中国没有完成 是的,在这些基本类别发布之前,没有经过严格的测试,所以对中文字符的支持不像 JavaSoft声称如此完美。不久前,我的一个技术朋友给我发了一封信,说他终于找到了 JavaServlet中文问题的根源。两个星期以来,他一直是JavaServlet的中文问题。 麻烦,因为每一个含有中文字符的字符串都必须强制转换才能得到正确的转换 结果(这似乎是公认的唯一解决方案)。后来,他真的不想这样继续安定下来 ,因为这样的事情真的不应该是高级程序员要做的事情,所以他找出了Servlet解码的源头 对代码进行分析,因为他怀疑解码部分的问题。经过四个小时的奋斗,他终于找到了 问题的根源在于。原来他的怀疑是正确的,Servlet的解码部分根本没有考虑双字节 ,直接用%XX作为字符。(原来JavaSoft也会犯这么低级的错误!) 如果你对这个问题感兴趣或者遇到了同样的麻烦,可以按照他的步骤对Servlet进行处理 .修改jar: 在HttpUtils中找到源代码的staticprivateStringparseName,并在返回前将sb(S tringBuffer)复制成bytebs[],然后returnnewstring(bs,“GB2312”)。作上 修改后需要自己解码: HashTableform=HttpUtils.parseQueryString(request.getQueryString())或者 form=HttpUtils.parsePostData(……) 别忘了把它放在Servlet上.jar里面。 5.Java中文问题总结 Java编程语言在网络世界中发展起来,这就要求Java对多国字符有很好的支持。
5.Java中文问题总结 Java编程语言在网络世界中发展起来,这就要求Java对多国字符有很好的支持。Java编程 语言适应了网络计算的需要,为网络世界的快速发展奠定了坚实的基础。J ava的创造者(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智能卡微处理器研发Java讨论组,领导BBS水木清华站316www68207295,为众多Java技术应用提供解决方案
![](/images/780-200-2.jpg)