JavaME中文编码

 

1. 简介

本文介绍JavaME中文编码的相关问题,这个问题一度是互联网上的开发者们讨论的热门话题。本文整理和综合了网上众多相关内容,尽可能的为开发者提供一个全面、系统的认识。

文中的代码仅用来说明原理,可能很不完整,缺乏变量定义或者返回值,请谅解。部分代码直接来源于网上的其他资料。

感谢众多开发者在中文编码问题上做出的努力与探索。总结中有什么问题的话,欢迎大家指正:)

 

2. 术语介绍

2.1 ASCII

基于罗马字母表的一套电子计算器编码系统,是单字节的编码方式,每个ASCII字符占用1个字节(8bits),所以ASCII编码最多可以表示256个字符。它是美国信息交换标准委员会(American Standards Committee for Information Interchange)的缩写, 为美国英语通信所设计。

显然ASCII编码用来表示英文字母和字符是足够了的,但是对于中文和日文等众多的文字来说,是远远不够的。

跟ASCII类似的编码还有ISO8859-1。

2.2 UNICODE

双字节编码方式,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本基准转换、处理的要求。UNICODE支持欧洲、非洲、中东、亚洲(包括统一标准的东亚像形汉字和韩国像形文字)的文字。

UNICODE又可以分为“高位在前”和“低位在前”的两种格式,这和CPU的处理方式有点关系。这一点可以通过BOM(Byte Order Mark)来标示,若采用 “低位在前”方式编码,BOM 会表示为 0xFF 0xFE,而在 Unicode 的定义中是不存在 U+FFFE 这个字符的。若采用高位在前方式编码,BOM 会表示为 0xFE 0xFF,而 U+FEFF 刚好是在 Unicode 中的有效字符,代表的是一个不占空间的 space 符号,所以即使没被解释为 BOM,也不会对阅览者产生错误的信息。

但UINICODE也带来一些问题,当美国人看见自己每天最常用的字符需要用两倍的空间来保存时,自然会觉得这是一种浪费,他们一定会说:看看那堆0。于是新的编码方式又诞生了。

2.3 UTF-8

UTF的全称是UCS Transformation Format,即把Unicode转做某种格式的意思。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32,本文讨论UTF-8格式。

UTF-8是UNICODE的一种变长字符编码,理论上使用1~6个字节来编码UNICODE。

虽然理论上UTF-8最多为6个字节,但是,由于双字节的Unicode最大为0XFFFF,所以双字节的Unicode转为UTF-8后最长为3个字节。

下列字节串用来表示一个字符。 用到哪个串取决于该字符在 Unicode 中的序号。

U-00000000 - U-0000007F: 0xxxxxxx 
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

上表中的xxx为Unicode编码的二进制数据。例如:“中”字,Unicode编码为4E2D。

Unicode: 4E 2D          01001110 00101101
UTF-8: E4 B8 AD  11100100 10111000 10101101

对于英文来说,UTF-8跟ISO8859-1一样节约;但显然中文等字符将为UTF-8付出更多。

2.4 GB2312

GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有6763个汉字。

GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160-254)。

GB2312具有很多扩展,其中GBK是微软对GB2312的扩展,GB18030则是2000年发布的国家标准,是到目前为止最新的国标汉字编码。

3.JavaME中的字符编解码

3.1 编解码方法

说到JavaME中的字符编码问题,自然要从String类入手,在String类中我们可以找到字符编解码的相关方法:

1. 解码:

public String(byte[] bytes, String enc) throws UnsupportedEncodingException

2. 编码:

public byte[] getBytes(String enc) throws UnsupportedEncodingException

举例来说,“诺基亚”三个汉字的GB2312编码为C5 B5 BB F9 D1 C7。

代码段一,解码试验:

byte[] codes = {0XC5, 0XB5, 0XBB, 0XF9, 0XD1, 0XC7};
String string = new String(codes, “gb2312”);
testForm.append(string);

得到的结果为:诺基亚

代码段二,编码试验:

byte[] codes = “诺基亚”.getBytes(“gb2312”);
for (int i = 0, t = codes.length; i < t; i ++) {
    String hexByte = Integer.getHexString(codes[i]);
    if (hexByte.length() > 2) {
 hexByte = hexByte.subString(hexByte.length() - 2);
    }
    testForm.append(“0X”+ hexByte.subString + “, ”);
}

得到的结果为:0XC5, 0XB5, 0XBB, 0XF9, 0XD1, 0XC7,

3.2 检查设备的编码支持情况

一个最直接的获取编码支持的方法是使用System.getProperty(“microedition.encoding”),可以得到设备的默认的字符编码,以NOKIA设备为例,得到的属性值为ISO8859-1。

然而,通过这个方法的意义并不大。首先,它只能获取到一个编码格式,而一般设备都会支持很多种编码规范;其次,这个属性的数值与虚拟机的实现有很大关系,同样以NOKIA S40v2为例,不论设备的目标市场使用什么语言,这个属性统一为ISO8859-1[参考资料5],显然ISO8859-1对于中文来说是毫无意义的。

再回过头来看看上一节中的两个方法,它们都会抛出一个UnsupportedEncodingException。利用这一点,我们可以自己来做一个设备支持编码规范情况的测试。

boolean isEncodingSupported (String encoding) {
    try {
 "诺基亚".getBytes(encoding);
 return true;
    } catch (UnsupportedEncodingException uee) {
 return false;
    }
}

这里需要提醒的是,对于同一个编码格式来说,可能会有很多种不同的名称,例如Unicode在NOKIA的设备上用的是ucs-2,再例如utf-8来说,utf-8、utf8和utf_8都会有可能。对于这一点,CLDC的规范中并没有给出严格的定义。所以在实际测试的过程中需要充分考虑到这个情况。

3.3 readUTF() 和 writeUTF(String)

CLDC中还有两个方法跟字符编码有关系:DataInputStream中的readUTF()和DataOutputStream中的writeUTF(String)。根据两个方法的Java Doc,writeUTF(String)首先会向输出流中写入字符串编码成UTF8格式后的byte数组长度(2个字节),然后再将这个UTF8的byte数组写入。而readUTF()则是先从输入流中读取2个字节,组成一个short数值,在从输入流中读出这个数值长度的byte数据,再将这个byte数组解码成字符串。详细说明请参考DataInputStream和DataOutputStream的Java Document。

 

转载自 http://azi.javaeye.com/blog/177491

 
 
<script></script>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值