MyException - 我的异常网
当前位置:我的异常网» Java Web开发 » 大家来讨论一下unicode和utf-8解决方案

大家来讨论一下unicode和utf-8解决方案(5)

www.MyException.Cn  网友分享于:2013-01-20  浏览:82次

UCS-2在BMP中开辟了一个特殊的区间(D800 - DFFF) -- 代理区,并平分成两个区,分别称为高半代理区(High-half Zone,D800 - DBFF),和低半代理区(Low-half Zone,DC00 - DFFF),各有1024个码位。使用时,从高低两个代理区中各取一个编码组成一个四字节的代理,来表示一个在BMP以外平面上的编码字符位。这样一来,总共可以多表示1024×1024个字符,映射到00群组中的01到10平面(共16个平面)。

代理对提供了用BMP的2字节编码来表示在基本多文种平面(BMP)之外的16个平面编码的机制。一些不常用的字符可以用代理对表示。目前,只有ISO/IEC 10646-2:2001和Unicode 3.1才使用到代理对。

高半代理区和低半代理区的划分,使编码位相互区分开。非代理区字符一定不会在这个区里。因为高半代理区和低半代理区不相交,所以很容易决定字符值的边界。一个完好的文本中,高半代理码和低半代理码总是按先后成对出现。

如果在实现上没有删除代理码或在代理码对中插入字符,数据的完整性就可得到保证。即使数据有残损,也只是局部的。一个残缺的码只影响一个字符。因为高半代理区和低半代理区不相交,且成对出现,错码不会传到文本的其它部分。

具体来说,一个代理对(H,L)由码值为D800-DBFF 的高半代理码H和码值为 DC00-DFFF低半代理码L组成。将一个字符映射到UCS-4码位中。假设N是UCS-4码值,则有:(以下所有数字均为16进制)

N = (H - D800) × 400 + (L - DC00) + 10000

于是得到N的码值为10000到10FFFF。

注意

Unicode 3.0没有用到代理对,直到3.1才增加了CJK Ext B,用到了02平面,需要使用代理对才能访问。但99.99%的情况下,根本用不到那些字。此外,JDK1.4只支持到Unicode 3.0,所以目前Java还不能应用代理对。

UTF编码
UTF为UCS Transformation Format的缩写,意为“UCS转换格式”。UCS只是一个字形和内码上的标准,并没有定义实际在计算机上存取的方法,而UTF便定义了一整套的计算机存取UCS编码的转换格式,并考虑了与其它编码方式兼容。常用的格式有UTF-8和UTF-16。有时也用到UTF-7来进行7位数据传输。

UTF-16 

UTF-16是用定长16位(2字节)来表示的UCS-2或Unicode转换格式。它将Unicode的编码值变成2字节的Big-endian(高位字节在前,低位字节在后)或Little-endian(低位字节在前,高位字节在后)编码。UTF-16利用代理对来访问BMP之外的字符编码。

Java使用Big-endian系统,而Intel系列处理器内部使用Little-endian系统(学汇编语言和C语言的人都知道)。

例如:“中国”两字,Unicode是4E2D 56FD,在Windows上用UTF-16编码,结果为四个字节:2D 4E FD 56;如果使用Java输出,结果为:4E 2D 56 FD。

使用UTF-16有什么缺点呢?很显然,

1. 所有原本1个字节就可以表示的西方字符,现在要用2个字节来表示,体积大了一倍。 

2. 学过C的人都知道,0x00代表C字符串的结尾。但是用UTF-16来表示单字节字符(ISO-8859-1)时,高位字节为0x00。这样就会使C语言库函数发生误判。用UTF-16表示文件名、网址等,全引出无数的问题。 

3. 字符的边界不好找。程序处理时必须从字符串的头部开始扫描,才可能正确地找出一个字符的边界,效率较低。此外,万一坏掉一个字节,这个字节之后的字符都会错位,坏掉一片。 

所有的这些问题,在UTF-8中都不存在。

但是,UTF-16也有其天然的优点:它直接表现了字符编码的整数值。所以UTF-16是最直接的Unicode表示法。此外,它是定长的,这大大简化了字符串的操作。Java语言就是用UTF-16格式将字符存储在内存中的。正是这样,才使Java的Unicode字符串的操作格外简单高效。

UTF-8 

UTF-8使用了变长技术,在每一个编码区域有不同的字码长度:

1. 对UCS-2,由1字节至3字节构成; 

2. 如果UCS-2使用了代理对,则UTF-8最长可到4字节; 

3. 对UCS-4,由1字节至6字节构成。 

因为以字节(8位)为组成单元,故称为“UTF-8”。对于英文文本,UTF-8的文件大小比其它转换格式都小。

在UTF-8内,字符由1个至6个字节为组合。下表列举出了不同范围的UCS码转换成UTF-8的规则。英文字母“x”代表可以用来记录 Unicode 码值的区域。

UCS-4 区域(十六进制)
 UTF-8字节组合(二进制)
 
0000 0000 —— 0000 007F 
 0xxxxxxx 
 
0000 0080 —— 0000 07FF 
 110xxxxx 10xxxxxx 
 
0000 0800 —— 0000 FFFF 
 1110xxxx 10xxxxxx 10xxxxxx 
 
0001 0000 —— 001F FFFF 
 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
 
0020 0000 —— 03FF FFFF 
 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
 
0400 0000 —— 7FFF FFFF 
 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
 


在UTF-8内,

1. 如果一个字节,最高位(第8位)为0,表示这是一个ASCII字符(00 - 7F)。可见,所有ASCII编码已经是UTF-8了。 

2. 如果一个字节,以11开头,连续的1的个数暗示这个字符的字节数,例如:110xxxxx代表它是双字节UTF-8字符的首字节。 

3. 如果一个字节,以10开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节。 

可见UTF-8可以有效地保证数据的完整性,避免出现编码的错位。即使偶然出现“坏字”,也不会影响到后续的文本。

那么UTF-8有什么缺点呢?显然,对于在BMP中的中文字来说,需要用3个字节才能表示,比使用UTF-16或直接使用双字节的GB2312编码大了0.5倍。

 

上文说了一大通,总结一下,其实很简单:

字符编码是抽象字符在计算机中的数字表示。 
字符编码集(character set,简称字符集)是一批字符编码的集合。世界上存在大量互不兼容的字符集,给国际交流带来了困难。 
ASCII码是最古老的字符编码,它总共只定义了7位共128个字母、数字和符号。但它是其它所有字符编码的基础。 
Unicode用16位整数编码,将世界上所有主要文字的字符统一起来了。如果利用代理对(surrogate pair)最多可以表示从0到1FFFF的字符。然而绝大多数情况下,只需要用到0到FFFF之间的字符就足够了。 
Unicode常用UTF-8和UTF-16来表示。7位的ASCII码不用作任何变化,就已经是UTF-8了。但UTF-8需要用3个字节来表示一个汉字。 
ISO 8859系列字符集,定义了单字节字符编码的标准。其中最特殊的是ISO-8859-1编码,它的编码和Unicode中最开始的256个字符编码完全相同。 
GB18030编码是中国大陆的国家标准,在字汇上等同于Unicode,在编码上和GB2312编码以及GBK编码兼容。 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sfdev/archive/2009/01/13/3770706.aspx

文章评论

软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有