JSP/Servlet 中的汉字编码问题

smilingdeng 2003-02-20 02:58:33
JSP/Servlet 中的汉字编码问题
JSP/Servlet DBCS IBM 网上就中字符编码问题有许多优秀的文章和讨论,本文对它们作一些整理,并结合
WebSphere Application Server 3.5 WAS ( )的解决方法作一些说明,希望它不是多余的。
1. 问题的起源
ASCII , GB2312-80 每个国家(或区域)都规定了计算机信息交换用的字符编码集,如美国的扩展码中国的,日
JIS / SBCS 本的等,作为该国家区域内信息处理的基础,有着统一编码的重要作用。字符编码集按长度分为(单字
DBCS 节字符集), (双字节字符集)两大类。早期的软件(尤其是操作系统),为了解决本地字符信息的计算机处
L10N LANG, Codepage 理,出现了各种本地化版本( ),为了区分,引进了等概念。但是由于各个本地字符集代码
范围重叠,相互间信息交换困难;软件各个本地化版本独立维护成本较高。因此有必要将本地化工作中的共性抽取
I18N 出来,作一致处理,将特别的本地化处理内容降低到最少。这也就是所谓的国际化( )。各种语言信息被进一
Locale Unicode 步规范为信息。处理的底层字符集变成了几乎包含了所有字形的。
Unicode 现在大部分具有国际化特征的软件核心字符处理都是以为基础的,在软件运行时根据当时的
Locale/Lang/Codepage Unicode 设置确定相应的本地字符编码设置,并依此处理本地字符。在处理过程中需要实现
Unicode 和本地字符集的相互转换,甚或以为中间的两个不同本地字符集的相互转换。这种方式在网络环境下被进
一步延伸,任何网络两端的字符信息也需要根据字符集的设置转换成可接受的内容。
Java Unicode Unicode V2.0 Java / / 语言内部是用表示字符的,遵守。程序无论是从往文件系统以字符流读写文
URL HTML URL 件,还是往连接写信息,或从连接读取参数值,都会有字符编码的转换。这样做虽然增加了编程
的复杂度,容易引起混淆,但却是符合国际化的思想的。
从理论上来说,这些根据字符集设置而进行的字符转换不应该产生太多问题。而事实是由于应用程序的实际运行
Unicode 环境不同, 和各个本地字符集的补充、完善,以及系统或应用程序实现的不规范,转码时出现的问题时时
困扰着程序员和用户。
2. GB2312-80 GBK GB18030-2000 , , 汉字字符集Encoding 及
JAVA 其实解决程序中的汉字编码问题的方法往往很简单,但理解其背后的原因,定位问题,还需要了解现有的
汉字编码和编码转换。
GB2312-80 9 是在国内计算机汉字信息技术发展初始阶段制定的,其中包含了大部分常用的一、二级汉字,和
区的符号。该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其
0xa1 0xfe 0xa1-0xfe 0xb0a1 0xf7fe 编码范围是高位- ,低位也是;汉字从开始,结束于;
GBK GB2312-80 20902 0x8140-0xfefe 是的扩展,是向上兼容的。它包含了个汉字,其编码范围是,剔除高位
0x80 Unicode 2.0 JAVA GBK 的字位。其所有字符都可以一对一映射到,也就是说实际上提供了字符集的支持。这
Windows 是现阶段和其它一些中文操作系统的缺省字符集,但并不是所有的国际化软件都支持该字符集,感觉是
GBK GB18030-2000 他们并不完全知道是怎么回事。值得注意的是它不是国家标准,而只是规范。随着国标的发
布,它将在不久的将来完成它的历史使命。
GB18030-2000(GBK2K) GBK GBK2K 在的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。从根本
上解决了字位不够,字形不足的问题。它有几个特点,
。它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。
GBK 。编码是变长的,其二字节部分与兼容;四字节部分是扩充的字形、字位,其编码范围是首字节
0x81-0xfe 0x30-0x39 0x81-0xfe 0x30-0x39 、二字节、三字节、四字节。
Unicode 3.0 。它的推广是分阶段的,首先要求实现的是能够完全映射到标准的所有字形。
。它是国家标准,是强制性的。
GBK2K 现在还没有任何一个操作系统或软件实现了的支持,这是现阶段和将来汉化的工作内容。
Unicode ...... 的介绍就免了吧。
JAVA encoding ( JDK ) 支持的中与中文编程相关的有: 有几个在文档中未列出
ASCII 7-bit, ascii7  同
ISO8859-1 8-bit, 8859_1,ISO-8859-1,ISO_8859-1,latin1... 同
GB2312-80 gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, 同
ISO2022CN,ISO2022CN_GB......
GBK ( ), MS936 注意大小写同
UTF8 UTF-8
GB18030 ( IBM JDK1.3.? ), Cp1392,1392 现在只有有支持同
1 of 4 2001-4-9 10:07
jsp/Servlet chinese encoding problem and sultions file:///E|/Docs/jsp_dbcs/jsp_dbcsz.html
JAVA Unicode . java Unicode 语言采用处理字符但从另一个角度来说,在程序中也可以采用非的转码,重要的是保
ISO-8859-1 证程序入口和出口的汉字信息不失真。如完全采用来处理汉字也能达到正确的结果。网络上流行的许多
解决方法,都属于这种类型。为了不致引起混淆,本文不对这种方法作讨论。
3. '?' 中文转码时、乱码的由来
   两个方向转换都有可能得到错误的结果:
Unicode-->Byte, 0x3f.  如果目标代码集不存在对应的代码,则得到的结果是
如:
"\u00d6\u00ec\u00e9\u0046\u00bb\u00f9".getBytes("GBK")
"?ìéF?ù", Hex 3fa8aca8a6463fa8b4. 的结果是值是
\u00ec 0xa8ac, \u00e9 \xa8a6... 仔细看一下上面的结果,你会发现被转换为被转换为它
GB2312 的实际有效位变长了! 这是因为符号区中的一些符号被映射到一些公共的符号
ISO-8859-1 SBCS Unicode 编码,由于这些符号出现在或其它一些字符集中,故它们在中
8 ( 编码比较靠前,有一些其有效位只有位,和汉字的编码重叠其实这种映射只是编码的
Unicode 映射,在显示时仔细不是一样的。中的符号是单字节宽,汉字中的符号是双字
) . Unicode\u00a0--\u00ff 20 节宽在之间这样的符号有个。了解这个特征非常重要!由
JAVA ( 此就不难理解为什么编程中,汉字编码的错误结果中常常会出现一些乱码其实是
), '?' , 符号字符而不全是字符就比如上面的例子。
Byte-->Unicode, Byte 0xfffd. 如果标识的字符在源代码集不存在,则得到的结果是
如:
Byte ba[] = {(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1};
new String(ba,"gb2312");
"? ", hex "\ufffd\u554a". 0x8140 GBK GB2312 结果是啊值是是字符,按转换表没有对应
\ufffd. ( uniCode 的值,取请注意:在显示该时,因为没有对应的本地字符,所以也适用
"?".) 上一种情况,显示为一个
JSP/Servlet 实际编程中, 程序得到错误的汉字信息,往往是这两个过程的叠加,有时甚至是两个
. 过程叠加后反复作用的结果
4. JSP/Servlet WAS 汉字编码问题及在中的解决办法
4.1 encoding 常见的问题的现象
JSP/Servlet encoding browser : 网上常出现的问题一般都表现在或应用程序端,如
Jsp/Servlet ’?’ ? 。浏览器中看到的页面中的汉字怎么都成了
Servlet 。浏览器中看到的页面中的汉字怎么都成了乱码?
JAVA 。应用程序界面中的汉字怎么都成了方块?
Jsp/Servlet GBK 。页面无法显示汉字。
。JSP <%...%>,<%=...%> Tag JAVA code 页面中内嵌在等包含的中的中文成了乱码,但页面
的其它汉字是对的。
Jsp/Servlet form 。不能接收提交的汉字。
JSP/Servlet 。数据库读写无法获得正确的内容。
……
3 Java font 隐藏在这些问题后面的是各种错误的字符转换和处理(除第个外,是因为设置错误引起
encoding Jsp/Servlet 的)。解决类似的字符问题,需要了解的运行过程,检查可能出现问题的各个点。
4.2 JSP/Servlet web encoding 编程时的问题
Java JSP/Servlet Browser HTML 运行于应用服务器的为提供内容,其过程如下图所示:
2 of 4 2001-4-9 10:07
jsp/Servlet chinese encoding problem and sultions file:///E|/Docs/jsp_dbcs/jsp_dbcsz.html
: 其中有字符编码转换的地方有
a. JSP Java JVM file.encoding JSP JAVA 编译。应用服务器将根据的值读取源文件,编译生成
file.encoding GBK 源文件,再根据值写回文件系统。如果当前系统语言支持,那么这时候不会出
encoding LANG en_US Linux, AIX Solaris 现问题。如果是英文的系统,如是的或,则要将
JVM file.encoding GBK GB2312 的值置成。系统语言如果是,则根据需要,确定要不要设置
file.encoding file.encoding GBK GBK ,将设为可以解决潜在的字符乱码问题。
b. Java .class JVM a. file.encoding 需要被编译为才能在中执行,这个过程存在与同样的问题。
servlet jsp Servlet 从这里开始和的运行就类似了,只不过的编译不是自动进行的。JSP 对于程
, JAVA ( sun.tools.javac.Main ). 序对产生的中间文件的编译是自动进行的在程序中直接调用类因
, encoding OS JSP JAVA Code 此如果在这一步出现问题的话也要检查和的语言环境,或者将内嵌在
Unicode, JAVA code Servlet, javac 中的静态汉字转为要么静态文本输出不要放在中。对于编
-encoding 译时手工指定参数就可以了。
c. Servlet HTML browser encoding 需要将页面内容转换为可接受的内容发送出去。依赖于各
JAVA App Server Browser accept-charset accept-language 的实现方式,有的将查询的和参数
encoding encoding 或以其它猜的方式确定值,有的则不管。因此采用固定也许是最好的解决方
JSP Servlet contentType="text/html; charset=GB2312" 法。对于中文网页,可在或中设置;
GBK contentType="text/html; charset=GBK" IE Netscape 如果页面中有字符,则设置为,由于和
GBK 对的支持程度不一样,作这种设置时需要测试一下。
16 JAVA char 8 Servlet 因为位在网络传送时高位会被丢弃,也为了确保页面中的汉字(包括内
servlet PrintWriter out=res.getWriter() 嵌的和运行过程中得到的)是期望的内码,可以用取代
ServletOutputStream out=res.getOutputStream(). PrinterWriter contentType 将
...全文
102 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧