Java 编程技术中汉字问题的分析及解决
--------------------------------------------------------------------------------
在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题。一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言默认的编码方式是UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢?本文将从汉字编码的常识入手,结合 Java 编程实例,分析以上两个问题并提出解决它们的方案。
--------------------------------------------------------------------------------现在 Java 编程语言已经广泛应用于互联网世界,早在 Sun 公司开发 Java 语言的时候,就已经考虑到对非英文字符的支持了。Sun 公司公布的 Java 运行环境(JRE)本身就分英文版和国际版,但只有国际版才支持非英文字符。不过在 Java 编程语言的应用中,对中文字符的支持并非如同 Java Soft 的标准规范中所宣称的那样完美,因为中文字符集不只一个,而且不同的操作系统对中文字符的支持也不尽相同,所以会有许多和汉字编码处理有关的问题在我们进行应用开发中困扰着我们。有很多关于这些问题的解答,但都比较琐碎,并不能够满足大家迫切解决问题的愿望,关于 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 修改过的数据库的内容在别的场合应用时无法继续正确地提供信息。 String sEnglish = “apple”; String sChinese = “苹果”; String s = “苹果 apple ”; sEnglish 的长度是5,sChinese的长度是4,而 s 默认的长度是14。对于 sEnglish来说, Java 中的各个类都支持得非常好,肯定能够正确显示。但对于 sChinese 和 s 来说,虽然 Java Soft 声明 Java 的基本类已经考虑到对多国字符的支持(默认 UNICODE 编码),但是如果操作系统的默认编码不是 UNICODE ,而是国标码等。从 Java 源代码到得到正确的结果,要经过 “Java 源代码-> Java 字节码-> ;虚拟机->操作系统->显示设备”的过程。在上述过程中的每一步骤,我们都必须正确地处理汉字的编码,才能够使最终的显示结果正确。 “ Java 源代码-> Java 字节码”,标准的 Java 编译器 javac 使用的字符集是系统默认的字符集,比如在中文 Windows 操作系统上就是 GBK ,而在 Linux 操作系统上就是ISO-8859-1,所以大家会发现在 Linux 操作系统上编译的类中源文件中的中文字符都出了问题,解决的办法就是在编译的时候添加 encoding 参数,这样才能够与平台无关。用法是 javac –encoding GBK。 “ Java 字节码->虚拟机->操作系统”, Java 运行环境 (JRE) 分英文版和国际版,但只有国际版才支持非英文字符。 Java 开发工具包 (JDK) 肯定支持多国字符,但并非所有的计算机用户都安装了 JDK 。很多操作系统及应用软件为了能够更好的支持 Java ,都内嵌了 JRE 的国际版本,为自己支持多国字符提供了方便。 “操作系统->显示设备”,对于汉字来说,操作系统必须支持并能够显示它。英文操作系统如果不搭配特殊的应用软件的话,是肯定不能够显示中文的。 还有一个问题,就是在 Java 编程过程中,对中文字符进行正确的编码转换。例如,向网页输出中文字符串的时候,不论你是用 out.println(string); // string 是含中文的字符串 还是用 <%=string%>,都必须作 UNICODE 到 GBK 的转换,或者手动,或者自动。在 JSP 1.0中,可以定义输出字符集,从而实现内码的自动转换。用法是 <%@page ContentType=”text/html;charset=gb2312” %> 但是在一些 JSP 版本中并没有提供对输出字符集的支持,(例如 JSP 0.92),这就需要手动编码输出了,方法非常多。最常用的方法是 String s1 = request.getParameter(“keyword”); String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”); getBytes 方法用于将中文字符以“ISO-8859-1”编码方式转化成字节数组,而“GBK” 是目标编码方式。我们从以ISO-8859-1方式编码的数据库中读出中文字符串 s1 ,经过上述转换过程,在支持 GBK 字符集的操作系统和应用软件中就能够正确显示中文字符串 s2 。
Java 中文问题的表层分析及处理背景 开发环境
JDK1.15
Vcafe2.0
JPadPro 服务器端
NT IIS
Sybase System
Jconnect(JDBC) 客户端
IE5.0
Pwin98
.CLASS 文件存放在服务器端,由客户端的浏览器运行 APPLET , APPLET 只起调入 FRAME 类等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。 I. 取中文 用 JDBC 执行 SELECT 语句从服务器端读取数据(中文)后,将数据用 APPEND 方法加到 TextArea(TA) ,不能正确显示。但加到 List 中时,大部分汉字却可正确显示。 将数据按“ISO-8859-1” 编码方式转化为字节数组,再按系统缺省编码方式 (Default Character Encoding) 转化为 STRING ,即可在 TA 和 List 中正确显示。 程序段如下: dbstr2 = results.getString(1); //After reading the result from DB server,converting it to string. dbbyte1 = dbstr2.getBytes(“iso-8859-1”); dbstr1 = new String(dbbyte1); 在转换字符串时不采用系统默认编码方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 两种情况下,从数据库取数据都没有问题。 II. 写中文到数据库 处理方式与“取中文”相逆,先将 SQL 语句按系统缺省编码方式转化为字节数组,再按“ISO-8859-1”编码方式转化为 STRING ,最后送去执行,则中文信息可正确写入数据库。 程序段如下: sqlstmt = tf_input.getText(); //Before sending statement to DB server,converting it to sql statement. dbbyte1 = sqlstmt.getBytes(); sqlstmt = newString(dbbyte1,”iso-8859-1”); _stmt = _con.createStatement(); _stmt.executeUpdate(sqlstmt); ……
--------------------------------------------------------------------------------
在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题。一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言默认的编码方式是UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢?本文将从汉字编码的常识入手,结合 Java 编程实例,分析以上两个问题并提出解决它们的方案。
--------------------------------------------------------------------------------现在 Java 编程语言已经广泛应用于互联网世界,早在 Sun 公司开发 Java 语言的时候,就已经考虑到对非英文字符的支持了。Sun 公司公布的 Java 运行环境(JRE)本身就分英文版和国际版,但只有国际版才支持非英文字符。不过在 Java 编程语言的应用中,对中文字符的支持并非如同 Java Soft 的标准规范中所宣称的那样完美,因为中文字符集不只一个,而且不同的操作系统对中文字符的支持也不尽相同,所以会有许多和汉字编码处理有关的问题在我们进行应用开发中困扰着我们。有很多关于这些问题的解答,但都比较琐碎,并不能够满足大家迫切解决问题的愿望,关于 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 修改过的数据库的内容在别的场合应用时无法继续正确地提供信息。 String sEnglish = “apple”; String sChinese = “苹果”; String s = “苹果 apple ”; sEnglish 的长度是5,sChinese的长度是4,而 s 默认的长度是14。对于 sEnglish来说, Java 中的各个类都支持得非常好,肯定能够正确显示。但对于 sChinese 和 s 来说,虽然 Java Soft 声明 Java 的基本类已经考虑到对多国字符的支持(默认 UNICODE 编码),但是如果操作系统的默认编码不是 UNICODE ,而是国标码等。从 Java 源代码到得到正确的结果,要经过 “Java 源代码-> Java 字节码-> ;虚拟机->操作系统->显示设备”的过程。在上述过程中的每一步骤,我们都必须正确地处理汉字的编码,才能够使最终的显示结果正确。 “ Java 源代码-> Java 字节码”,标准的 Java 编译器 javac 使用的字符集是系统默认的字符集,比如在中文 Windows 操作系统上就是 GBK ,而在 Linux 操作系统上就是ISO-8859-1,所以大家会发现在 Linux 操作系统上编译的类中源文件中的中文字符都出了问题,解决的办法就是在编译的时候添加 encoding 参数,这样才能够与平台无关。用法是 javac –encoding GBK。 “ Java 字节码->虚拟机->操作系统”, Java 运行环境 (JRE) 分英文版和国际版,但只有国际版才支持非英文字符。 Java 开发工具包 (JDK) 肯定支持多国字符,但并非所有的计算机用户都安装了 JDK 。很多操作系统及应用软件为了能够更好的支持 Java ,都内嵌了 JRE 的国际版本,为自己支持多国字符提供了方便。 “操作系统->显示设备”,对于汉字来说,操作系统必须支持并能够显示它。英文操作系统如果不搭配特殊的应用软件的话,是肯定不能够显示中文的。 还有一个问题,就是在 Java 编程过程中,对中文字符进行正确的编码转换。例如,向网页输出中文字符串的时候,不论你是用 out.println(string); // string 是含中文的字符串 还是用 <%=string%>,都必须作 UNICODE 到 GBK 的转换,或者手动,或者自动。在 JSP 1.0中,可以定义输出字符集,从而实现内码的自动转换。用法是 <%@page ContentType=”text/html;charset=gb2312” %> 但是在一些 JSP 版本中并没有提供对输出字符集的支持,(例如 JSP 0.92),这就需要手动编码输出了,方法非常多。最常用的方法是 String s1 = request.getParameter(“keyword”); String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”); getBytes 方法用于将中文字符以“ISO-8859-1”编码方式转化成字节数组,而“GBK” 是目标编码方式。我们从以ISO-8859-1方式编码的数据库中读出中文字符串 s1 ,经过上述转换过程,在支持 GBK 字符集的操作系统和应用软件中就能够正确显示中文字符串 s2 。
Java 中文问题的表层分析及处理背景 开发环境
JDK1.15
Vcafe2.0
JPadPro 服务器端
NT IIS
Sybase System
Jconnect(JDBC) 客户端
IE5.0
Pwin98
.CLASS 文件存放在服务器端,由客户端的浏览器运行 APPLET , APPLET 只起调入 FRAME 类等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。 I. 取中文 用 JDBC 执行 SELECT 语句从服务器端读取数据(中文)后,将数据用 APPEND 方法加到 TextArea(TA) ,不能正确显示。但加到 List 中时,大部分汉字却可正确显示。 将数据按“ISO-8859-1” 编码方式转化为字节数组,再按系统缺省编码方式 (Default Character Encoding) 转化为 STRING ,即可在 TA 和 List 中正确显示。 程序段如下: dbstr2 = results.getString(1); //After reading the result from DB server,converting it to string. dbbyte1 = dbstr2.getBytes(“iso-8859-1”); dbstr1 = new String(dbbyte1); 在转换字符串时不采用系统默认编码方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 两种情况下,从数据库取数据都没有问题。 II. 写中文到数据库 处理方式与“取中文”相逆,先将 SQL 语句按系统缺省编码方式转化为字节数组,再按“ISO-8859-1”编码方式转化为 STRING ,最后送去执行,则中文信息可正确写入数据库。 程序段如下: sqlstmt = tf_input.getText(); //Before sending statement to DB server,converting it to sql statement. dbbyte1 = sqlstmt.getBytes(); sqlstmt = newString(dbbyte1,”iso-8859-1”); _stmt = _con.createStatement(); _stmt.executeUpdate(sqlstmt); ……
解决方案 »
- 写JSP文档遇到的一个问题,应该简单的哈。。
- 在线等,大家来帮忙
- 那位知道eclipse3.1在使用hibernate的create hibernate mapping的具体步骤
- 请问如何把PDF文件创建成.jpg文件
- 浏览器不能直接打开jsp文件?(急!!!!!!!!!!)
- 我是rose的初学者,想知道 用例图中的 “NewSystem”那个控件在那里能找的到?同时想结交一些学rose的朋友。
- 哪里有比较好的jsp源程序
- 如何取得hp unix环境下的环境变量?(apache+tomcat),非常着急,在线等待...
- 在tomcat下运行正常,iis+tomcat报错
- Servlet在本地部署没有问题,放到服务器上却出问题了,求助
- 环境变量问题
- 请教一个概念的问题
我曾经给外交部做过一个CMS系统Demo,系统中同时支持所有Unicode支持的国家和语言,实际上并不难。
坚持一个原则:保证编码一致性。
无论从存储环节(比如文件、数据库)、网络传输环节(传出、传入),还是特别的系统的编码解码环节(例如使用某个XMLParser或自己的应用系统),每个环节管好自己:input的数据如果是A编码,那么就用A编码Decode,然后可以以任何编码Output。下一个环节得到后,一样的按照上一个环节的编码进行解码(理解)即可。就好比大学里朋友们经常玩的一个游戏:大家围成一圈用各自的方言传话,到最后一个看看是否和原话相同。这个游戏之所以有趣,就是因为大家的方言不同,理解上一个人的说话出现了问题,于是往下传就出错了。(电视里也经常有这样的游戏,比如用手语等)举个例子:如果网页中用了GB2312的编码,此时用户如果用IE和支持Unicode的输入法填写了一个form,提交后jsp应该用什么编码理解呢?显然是GB2312。呵呵,这里面有一个有意思的事情就是如果你在简体中文环境下,在BIG5编码的Web中提交form,JSP应该用BIG5来“理解”它!(去台湾bbs关税其实不用安装特别的软件的,用微软拼音输入法并选择繁体字即可,IE会自动转码)
JSP得到传递过来的参数,如果按照正确的编码进行解码,此时要写入数据库,该用什么编码呢?本来无所谓,你用编码A写入数据库,等程序从数据库取出来的时候也用A解码即可,但对于Oracle和SQLServer的不同驱动程序有些不同——有的驱动程序会对你传入的数据按照数据库的代码设置进行“解释”,中间转了一次码。所以需要测试一下,如果没有发生这样的情况,那么只需要用写入数据库的编码来理解从数据库读出的数据即可。随后,JSP“拿着”已经“正确理解”的数据,可以“翻译”成任何别的编码再告诉下一个环节——浏览器。此时,你的JSP输出的如果是BIG5的string,那么该Web的编码也需要是BIG5,否则浏览器会用错误的方式去“理解”,造成乱码。IBM developworks上的文章仔细的分析了内码、字符集、字库之间的关系,不太明白的可以好好看看。其实很多情况下我们所谓的“汉字问题”不是内码的问题,有时候是字库混淆了我们的理解——比如说繁体字未必就是BIG5码!日文字未必就是JIS字符集!
我们只要记住遵循“脱衣法则”,编码和解码之间按顺序匹配进行就不会乱了。
如果一个环节和另外一个环节之间,不知道是什么意外的打乱了你的匹配,其实不说明我上面说的有错误,关键是检查一下你所用的软件环境,是不是你漏掉了某个环节的编码匹配——比如xmlparser、application server的编码设置。
<html>
<title>信息输入表单</title>
<body>
<%@ page contentType="text/html;charset=gb2312"%>
<form action="ch8-1a.jsp" method="post">
<table border="1">
<tr><td bgcolor="orange">姓名:</td><td><input type="text" name="name"></td></tr>
<tr><td bgcolor="orange">性别:</td><td>
<input type="radio" name="sex" value="男" checked>
<input type="radio" name="sex" value="女">
</td></tr>
<tr><td bgcolor="orange">喜好颜色:</td><td><select size="1" name="color">
<option selected>none
<option>blue
<option>green
<option>red
<option>yellow
</select>
</td></tr>
<tr><td bgcolor="orange">兴趣:</td>
<td><select size=5 name="hobby" multiple>
<option>唱歌
<option>看电影
<option>逛街
<option>游泳
<option>画图
</select>
</td></tr>
<tr><td colspan="2" align="center">
<input type="submit" value="提交信息">
</td></tr>
</form>
</table>
</body>
</html>
//-------------------------------------------ch8-1a.jsp
<%
response.setContentType("text/html;charset=gb2312");
String name=request.getParameter("name");
String sex=request.getParameter("sex");
String color=request.getParameter("color");
String hobby[]=request.getParameterValues("hobby");
String hobbies=" ";
int count=hobby.length;
for(int i=0;i<count-1;i++)
hobbies=hobbies+"<"+hobby[i]+">";
Cookie nameCookie=new Cookie("name",name);
Cookie sexCookie=new Cookie("sex",sex);
Cookie colorCookie=new Cookie("Color",color);
Cookie hobbyCookie=new Cookie("hobby",hobbies);
response.addCookie(nameCookie);
response.addCookie(sexCookie);
response.addCookie(colorCookie);
response.addCookie(hobbyCookie);
response.sendRedirect("ch8-1b.jsp");
%>
//---------------------------------------ch8-1b.jsp
<html>
<title>取得Cookie中的信息</title>
<body>
<%@ page contentType="text/html;charset=gb2312"%>
<%
Cookie cookies[]=request.getCookies();
int count=cookies.length;
String name=null,sex=null,color=null,hobbies=null;
for(int i=0;i<count;i++)
if(cookies[i].getName().equals("name"))
name=cookies[i].getValue();
else if(cookies[i].getName().equals("sex"))
sex=cookies[i].getValue();
else if(cookies[i].getName.equals("color"))
color=cookies[i].getValue();
else if(cookies[i].getName.equals("hobbies"))
hobbies=cookies[i].getValue();
%>
<font color="<%=color%>" size="5"><%=name%></font>
你好!以下是你的个人信息...<p>
<%
out.println("性别:<br>");
if(sex.equals("男"))
out.println("我是男生<p>");
else
out.println("我是女生<P>");
out.println("兴趣"+hobbies+"<br>");
%>
</body>
</html>
/==>>>>>>>>>>>>>>>>>>>>>>>>>怎么这里显示中文出错????
你说的是中文的字符串匹配问题么?
我用的是正则表达式(JDK1.4以前是不带在jdk中的),unicode下没什么问题,不知道你说的是什么情况?