[概述]
在编程中字符编码绝对是个值得重视的问题,当读取一个文件或是得到一个输入流,你需要分析数据的编码方式、形态,以便能正确的处理、显示数据所表示的字符。
[细节]
1) 在简体中文操作系统中,从键盘输入的原始字符采用的是GBK编码方式,对应到其他操作系统,采用的应是系统默认的本地字符集。而在程序设计语言中,字符和字符串则通常是使用Unicode编码方式,这一点可以用下列代码说明(使用Java语言描述)。
int ch = System.in.read(); //从键盘输入中读取一个字节的数据
如果输入“中国”两个字符,使用上面的代码将所有的数据读取,将得到“D6 D0 B9 FA”,这写数据正是“中国”两个字符的GBK编码值。
String tmp = "中国"; //定义字符串并赋值
for(int i=0;i<tmp.length();i++)
{
//将字符串中的每个字符编码值以十六进制形式显示
System.out.println(Integer.toHexString(ch));
}
上面代码最后显示的内容是“4E2D 56FD”,而这正是“中国”两个字符的Unicode编码值。
2) 不仅是输入的原始字符采用GBK编码,屏幕输出的最终数据也要采用GBK编码,下面的代码能说明问题。
String tmp = "中国"; //定义字符串并赋值
System.out.println(tmp); //将字符串tmp输出到显示屏
代码运行后,在显示屏上显然能看到“中国”两个字符,而字符串tmp分明是采用Unicode进行编码的,是不是刚才提出的命题站不住脚呢?其实,在调用println()方法后,该方法自动的将字符串tmp的编码方式从Unicode转换成了本地编码GBK,这样才能在屏幕上正常的显示中文。如果你仍然怀疑,请继续往下看。
byte [] buf1 = tmp.getBytes("Unicode"); //将字符串tmp以Unicode编码方式储存在字节数组中
byte [] buf2 = tmp.getBytes("GB2312"); //将字符串tmp以UGBK编码方式储存在字节数组中
//在屏幕输出流中直接写字节数组
System.out.write(buf1);
System.out.write(buf2);
这样的作法将会得到什么结果呢?结果也许会令你感到惊讶,buf1的数据输出后显示为乱码,而buf2的数据输出后赫然显示为“中国”两个字符。可以把命题说得明确点:如果要在屏幕上输出汉字,那么字符的最终编码方式必须是GBK编码方式。对于数字和英文字母,以及ASCII编码集中包含的符号,字符的最终编码方式可以是ASCII,这种情况下如果使用Unicode编码,那么显示的结果会是这样“1 2 3 a b c ”,本来想显示的内容是“123abc”。显示结果字符间多了个貌似空格的字符,这是因为ASCII编码使用一个字节,Unicode编码使用两个字节,在ASCII编码转换为Unicode时候,只是单纯地在编码值前面补充一个全为0的字节,这个字节在最终显示的时候被看做是空字符NUL。
3) 在涉及网页、网络流和关系数据库方面编程的时候,字符编码总喜欢戏弄编程人员,不花心思去驯服它的结果将是得到一堆乱码。例如在读取数据数据时候,数据库中的内容是中文字符,如果数据库没有考虑到中文支持问题就很容易得到乱码。再例如程序运行的平台默认编码并非GBK,在获取GBK编码的字符数据时候,程序会将数据看作默认编码,这样也容易产生乱码。在上述情况中编写程序的时候,就应该耐心的分析数据的编码方式,合理的编写代码防止乱码。
[例子]
记得在《Java手机程序设计入门与应用》(王森 编著)一书的第13章-MIDP网络程序设计中有一段使用HTTP进行网络连接的实例代码,部分代码如下所示。
String url = "
http://127.0.0.1/test.html
";
HttpConnection hc = (HttpConnection)Connector.open(url);
DataInputStream dis = new DataInputStream(hc.openInputStream());
String content = "";
int ic;
while((ic = dis.read()) != -1)
{
content += (char)ic;
}
Form f = new Form("HTTP Test");
f.append(content);
Display.getDisplay(this).setCurrent(f);
这段代码让手机通过HTTP协议与网络中的主机进行通信,然后获得网络主机上的文件test.html并将文件内容读取到字符串变量中,最后显示到程序窗体中。如果程序这般执行的话,你会发现MIDlet显示出来中文都是乱码。作者称“之所以会有这种结果,原因在于我们的仿真器支持Unicode的缘故。”,作者的意思似乎是MIDlet将本地编码的字符数据误认为了Unicode编码的数据,因此不能正常显示,然后推荐了一种解决方法:使用ASCII形态的Unicode。
所谓ASCII形态的Unicode指的是使用ASCII编码的字符来表示Unicode编码值,反过来说就是将Unicode的编码值看做字符,再用ASCII对这些字符进行编码存放。比如“中国”这两个字符的ASCII形态的Unicode编码字符为“\u4e2d\u56fd”,0x4E2D 0x56FD 分别为“中”和“国”的Unicode编码值,将编码值作为字符,然后在前面添加“\u”标识符,以便进行还原。再对这些字符进行ASCII编码就得到了ASCII形态的Unicode编码值,最终的值为“5C 75 34 65 32 64 5C 75 35 36 66 64”,一共12个字节的数据,分别对应了“\u4e2d\u56fd”中的一个字符。使用jdk*\bin文件夹下的native2ascii.exe程序可以很方便的将一个文件转换为ASCII形态的Unicode编码。将文件test.html转换形态后,MIDlet中需要再次将ASCII形态的Unicode转换为Unicode编码,这个转换方法需要自己写,最后MIDlet中显示出来的就是正常的中文字符。
在我看来,那本书的作者没有把握住问题的真正原因,也或许是我们使用的模拟器和平台不同。如果把握住真正的原因,问题的解决方法就变得很简单了。前面说过,要在屏幕上显示出中文,字符的最终编码形式必须是GBK,在中国大陆发现的手机都能显示中文,也就说明手机中都支持GBK编码。那为什么会出现中文字符乱码的问题呢?我的理由是手机中采用的默认编码是ISO8859-1,对于从网络中读入的字符数据,在没有指明的情况下,MIDlet一律将它们看作是ISO8859-1编码的数据。而test.html的编码方式是GBK,MIDlet犯了个错误,它将GBK编码的数据误认为了ISO8859-1编码的数据,然后在显示的时候又进行了一次ISO8859-1到GBK的编码转换,这样的结果是数据遭到了破坏,显示出来的中文也就变成了乱码。
把握住了原因,解决起来就十分方便了。既然MIDlet将GBK编码的数据误认为ISO8859-1编码的数据,那么我们只要在程序中指明数据的编码方式就可以了,而不用使用“ASCII形态的Unicode”这样的舍本求末的方法。下面是解决MIDlet网络连接中文乱码问题的代码,这些代码将证明我的观点。
http://127.0.0.1/test.html;
HttpConnection hc = (HttpConnection)Connector.open(url);
byte [] buf = new byte[1024];
int len = hc.openInputStream().read(buf); //读取网络数据
String content = new String(buf,0,len,"GB2312"); //指定数据为GBK编码
Form f = new Form("HTTP Test");
f.append(content);
display.setCurrent(f);
上述代码中关键的一句是:
String content = new String(buf,0,len,"GB2312");
这句代码告诉MIDlet从网络中读取的数据使用的是GBK编码方式,然后MIDlet便能争取处理和显示这些数据。
如果将这句代码改写为:
String content = new String(buf,0,len);
或者是:
String content = new String(buf,0,len,"ISO8859-1");
都将出现同样的中文乱码现象,由此断定错误的原因是手机默认编码使用ISO8859-1,MIDlet将从网络中读取的GBK编码的数据误认成了ISO8859-1编码的数据。
分享到:
相关推荐
VC++编程实现转换文本文件的字符编码,在多种字符编码之间转换的方法
字符编码查看器是一款非常实用优秀的编程软件。这款软件支持编码之间的相互转换,可以帮助用户快速查看编码等。功能非常强大。需要的朋友可以前来本站下载。 软件介绍 字符编码查看器是一款可以帮助你轻松快速的...
对于给定的长度不超过6 的升序字符串,编程计算出它在上述字典中的编码。 Input 输入数据第一行给出一个字符串。 Output 程序运行结束时,将计算结果输出字符串的编码。 Sample Input a Sample Output 1
本书主要表现Unicode编码的平面数、编码方法、码位数、字符字节数、字符区域划分等重要概念 通过UTF32、UTF-16、UTF-8以及ANSI之间的对比表现字符字节数的变化规律。表现Windows操作系统个版本与Unicode之间的关系。...
用于汉字编码或其它字符编码分析,结合编程工具实现图形化界面的特殊字符操控。
霍夫曼编码,对输入的字符集和各个字符对应的权值,例如A={a,b,c,d,e,f,g,h},各个字符对应的权值为{5,29,7,8,14,23,3,11},求出每个字符的霍夫曼编码。 【输入形式】 输入若干个字符(1 ),其权值为int型。 输入...
根据前一阵的编程经验及实验,对各种乱码问题的解决方法进行总结并进一步研究了乱码产生的原因。
其实 JSP/Servlet 的中文encoding 并没有想像的那么复杂,虽然定位和解决问题没有定规,各种运行环境也各不尽然,但后面的原理是...不过,随着中文字符集的变化,不仅仅是 java 编程,中文信息处理中的问题还是会存在一
附录A.字符编码_3在LinuxC编程中使用Unicode和UTF-8[总结].pdf
包括ASCII,Unicode,UTF-8编码的详细结构,基本原理,编程技巧的讲解
也即,java程序在被编译前,我们的JAVA源程序文件是采用操作系统默认支持的file.encoding编码格式保存的, java源程序中含有中文信息字符和英文程序代码;要查看系统的file.encoding参数,可以用以下
提供了多种字符编码和转换的功能,如输入和输出字符的实体、ASCII码、八进制转义字符、十六进制转义字符等,以及支持多个字符的批量转换和显示。本资源适合C语言编码和转换的学习者和工程师使用,帮助他们通过Web...
C#编程总结(九)字符编码 - 停留的风 - 博客园.mhtml
(精品)用VC-编程实现转换文本文件的字符编码.pdf
对于给定一个字符串的编号,迅速解码出它在上述字典中的字符串编码。 数据输入 输入数据由input.txt提供。文件的第一行为一个整数N (1,000),表示字符串 的编号。 数据输出 输出该编号做对应的字符串编码到ouput.txt...
字符集与编码方式简介 英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编
使用C++编程含有a,b,c的LZW编码 添加关于待编码字符串是否符合要求的检验程序段
搞清常用编码特性是解决字符集编码问题的基础。字符集编码的识别与转换、分析各种乱码产生的原因、编程操作各种编码字符串(例如字符数计算、截断处理)等都需要弄清楚编码的特性。 了解一种字符集编码主要是要了解...
本文档介绍了几种从字符串中提取连续的字符数字转换为整数的方法,附有源代码供参考,适合于那些想要编码实现字符串中提取连续的字符数字转换为整数的同学
TXT文本的编码问题 1 VC++的Unicode编程 4 字符,字节和编码 - Characters, Bytes And Encoding 14 Unicode:宽字节字符集 23 ANSI and Unicode strings 26 UTF8与ANSI等编码间如何转换 27 ANSI ...