作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com
写于:2002/08 最后更新:
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.chedong.com/tech/unicode_java.html
关键词:i18n java jvm locale 乱码
内容摘要:
Java对输入输入首先有一个“字节流”到“字符流”之间的编码/解码过程,这个设置是根据系统配置决定的,为什么PHP之类的应用很少有字符集问题而Java有很好的国际化机制,却经常出现乱码问题呢?
简单的举例:
有一个包含“你好”这2个中文字的文件实际上是4个字节组成的:C4 E3 BA C3
在英文操作系统中缺省的编码解码方式是缺省编码方式是ISO8859,所以直接从文件中读取的结果是4个的字节,按ISO8859解码后在程序中操作的是4个Java字符,虽然每个JAVA字符是16位Unicode,但每个字符仍是8位字节的映射\u00C4\u00E3\u00BA\u00C3,因此处理的仍是“英文”。而显示过程中,是浏览器将字节流正确的显示成了相应的中文。
而一个Java应用在GBK编码方式的操作系统中,直接从文件中读取4个的字节后,按GBK方式解码后是2个16位的Java字符\u4F60\u597D,每个字都是相应Unicode的CJK区块所对应的中文。
更多的例子请参考:Java的中文处理学习笔记
这也就是为什么在php等应用很少出字符集问题的原因:在服务器端环境缺省一般是英文(ISO8859-1),等于全部处理使用的都是按字节方式处理的。数据输入输出过程中编码方式完全不被改动,因此乱码问题很少出现。而Java实际上提供了把每个中文直接当成1个“字”而不是2个字节处理的机制,主要的乱码问题往往是输入输出时编码解码方式不一致造成的。而且通过Unicode机制,程序除了实现程序界面根据本地化的适应外,甚至程序处理的内容本身的在不同字符集的操作系统中也是可以通用的,比如:在繁体中文操作系统中编辑的内容,在简体中文操作系统中也能正常的查询。以下例子可能更说明问题:
通过GNU/Linux系统的本地化设置让JAVA应用支持中文
Java 编程技术中汉字问题的分析及解决这篇直到最近还经常被一些网站转贴的文章中有一个例子说明了很多中国程序员遇到汉字乱码问题的思路:"GB2312 it"(汉化)
原文如下:
>>>>>>>
......前不久,我的一位技术上的朋友发信给我说,他终于找到了 Java Servlet 中文问题的根源。两周以来,他一直为 Java
Servlet
的中文问题所困扰,因为每面对一个含有中文字符的字符串都必须进行强制转换才能够得到正确的结果(这好象是大家公认的唯一的解决办法)。后来,他确实不想如此继续安分下去了,因为这样的事情确实不应该是高级程序员所要做的工作,他就找出
Servlet 解码的源代码进行分析,因为他怀疑问题就出在解码这部分。经过四个小时的奋斗,他终于找到了问题的根源所在。原来他的怀疑是正确的,
Servlet 的解码部分完全没有考虑双字节,直接把 %XX 当作一个字符。(原来 Java Soft 也会犯这幺低级的错误!)
如果你对这个问题有兴趣或者遇到了同样的烦恼的话,你可以按照他的步骤对 Servlet.jar 进行修改:
找到源代码 HttpUtils 中的 static private String parseName ,在返回前将
sb(StringBuffer) 复制成 byte bs[] ,然后 return new
String(bs,”GB2312”)。作上述修改后就需要自己解码了:
HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者
form=HttpUtils.parsePostData(……)
千万别忘了编译后放到 Servlet.jar 里面。
......
<<<<<<<<<
请问这位“高级”程序员几个问题:
也许我错了,但我的感觉是犯低级错误的不是JAVA:
如何设置可以让GNU/Linux从系统层次就支持中文编码(让JVM缺省的file.encoding就按照中文GB2312或者GBK进行编码解码)呢?
以上这篇文章发表在2000年年底,当时的GNU/Linux的内核是基于glibc-2.1开发的,而GLIBC2.1对中文的locale支持还有限,因此,在GNU/Linux上不能根据locale的设置将系统缺省的编码方式变成GB2312,从而改变JVM缺省的编码方式。关于GNU/Linux对l10n的支持请看:GNU/Linux程序员必读:中文化与GB18030标准。所以在redhat6.x下,无论你怎么设置locale,系统缺省的缺省file.encoding都是ISO_8859_1。
在redhat7.x 系统内核所基于的glibc-2.2.x对l10n有了更完整的支持,所以可以通过设置
LC_ALL=zh_CN.GB2312;export LC_ALL
LANG=zh_CN.GB2312;export LANG
让系统缺省的编码方式变成GB2312。JVM会根据系统的缺省编码方式设置系统的file.encoding属性。之后,应用中任何字节流到字符流的转换,JVM都会按照这一系统缺省编码方式进行转换。因此在基于glibc-2.2以上的GNU/Linux上是可以通过locale的设置来改变系统缺省的编码方式,从而改变上层Java应用的缺省编码、解码方式的。
locale设置对JVM file.encoding的影响可以我通过做过的一个试验说明:hello_unicode.html
由此可见:
通过web.xml设置解决URLEncoder.encode()方法和系统缺省编码方式相关的问题
在我所理解的范围内,J2SE 1.3中非常不符合Java的国际化规范的是在使用URLEncoder的时候:
比如在中文WIN98上运行的应用,使用URLEncoder.encode(String
s)时:比如“中文”这2个字符直接被Encoding的话结果是"%3F%3F"=>"??"。原因很简单,“中文”在encode()过程中应该先按GBK编码方式编码成4个字节(\u00d6\u00d0\u00ce\u00c4)后再进行URLEncoding才是正确的。这个在J2SE1.4中也修正了。方法encode(String
s)已经不鼓励使用,取而代之的是除了需要进行URLEncoding的字符串外,同时需要指定字符串编码方式的encode(String s,
String enc)。这样,URLEncoder就可以和系统缺省的编码方式无关了。
在J2SE1.3下一个WEB应用如果有这个问题可以通过在WEB-INF/web.xml中设置character-encoding来解决:
<web-app character-encoding="your_system_default_file.encoding">
...
</web-app>
比如:产品是在中文WINDOWS98中运行,系统缺省字符集是用GBK,则这个应用的web.xml需要设置成:
<web-app character-encoding="GBK">
...
</web-app>
UniCode inside, Localization outsite
以上2个方法仍然只是让应用更方便地本地化了,而应用本身并不是真正的国际化应用。设想一下如何设计一个全球的论坛系统:可以让中文和日文的用户都可以方便的浏览发表呢?在数据中间处理阶段应该以那种字符集存储呢?答案很简单:UniCode。以前很多文章都有关于如何设计一个国际化界面的介绍,只是应用的本地化界面输出,但很少提及数据在中间处理过程中如何适应国际化。
输入和存储阶段就用UniCode方式进行处理和存储,以方便应用以后的国际化。GOOGLE的设计就是一个非常好的国际化应用榜样,我以GOOGLE搜索引擎的国际化支持为例说明如何实现国际化应用的设计。
GOOGLE用户经常有这样的感觉:
首先我将GOOGLE对查询的处理流程简单的说明如下:
具体说明:
从以上的分析中我们可以看出:UniCode非常漂亮的解决了应用的国际化问题。对于应用前端来说,剩下的工作就是根据本地编码环境进行本地化的过程了。
如果应用的开发只是满足于在国内市场自给自足,“汉化”的思路的大量出现是很自然的。但要是把“汉化”比作UCDOS和RichWin的话,那么这种汉化方式迟早要被内核汉化的WIN95淘汰的。毕竟核心级别对国际化的支持才是一个真正简化前端应用设计、通用的解决方案。Microsoft和Sun等国际化大公司的产品从一开始就是为全球市场设计的,因此对国际化的支持一致非常重视。相比之下国内软件行业对相应国际标准显然重视不足,也很少积极地参与相关标准制定。
参考文档:
Java i18n
http://java.sun.com/docs/books/tutorial/i18n/index.html
Linux 国际化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
GNU/Linux 程序员必读:中文化与GB18030标准
http://www.ccidnet.com/tech/os/2001/07/31/58_2811.html
UniCode FAQ
http://www.cl.cam.ac.uk/~mgk25/UniCode.html
http://www.linuxforum.net/books/UTF-8-UniCode.html
(中文版)
Java 编程技术中汉字问题的分析及解决
http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml
汉字的编码方式:
http://www.unihan.com.cn/cjk/ana17.htm
*注释:l10n i18n都是缩写:用的是英文单词的首尾字母和其间字母个数
l10n: localization 本地化
i18n: internationalization 国际化
原文出处:<a
href="http://www.chedong.com/tech/unicode_java.html">http://www.chedong.com/tech/unicode_java.html</a>
<<返回