UTF-8编解码之说明

来源:互联网 发布:现世与冥界的逆转 知乎 编辑:程序博客网 时间:2024/06/05 18:16
我们知道ASCII码表中总共只有值在0-127之间的128个字符,用其表示纯粹的英文字符等已经足够了,而正是基于此产生了ANSI字符集。ANSI字符集中每个字符都是以一个8位的字节表示,但是后来随着全球信息化的加强,各国的语言都需要得到相应的体现,于是就出现了宽字符集,再后来就出现了unicode字符集,unicode又有UCS-2 和 UCS-4两种标准,不过通常unicode字符集中每个字符用两个字节来表示,这种表示方法就能囊括目前各国的语言字符,并且能有扩展的空间。而UTF8更是对传统的unicode等长字符表示方式的一种改进,它采用的较为灵活的变长方式,这样能够在概率上做到空间上的节省。下面是UTF8的原理说明。

UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。值得强调的是,UTF-8只是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

当要表示的内容是 7位 的时候就用一个字节:0******* 第一个0为标志位,剩下的空间正好可以表示ASCII 0-127 的内容。

当要表示的内容在 8 到 11 位的时候就用两个字节:110***** 10****** 第一个字节的110和第二个字节的10为标志位。

当要表示的内容在 12 到 16 位的时候就用三个字节:1110***** 10****** 10****** 和上面一样,第一个字节的1110和第二、三个字节的10都是标志位,剩下的所有*的位置都应该根据实际数据加以填充有效数据。

以此类推:
四个字节:11110**** 10****** 10****** 10******
五个字节:111110*** 10****** 10****** 10****** 10******
六个字节:1111110** 10****** 10****** 10****** 10****** 10******

下面的参考文章出自http://blog.csdn.net/xiongchen/archive/2006/04/10/657068.aspx,我觉得总结的很好,尤其是这里有关于Surrogate Pair 的说明特粘贴至此:

一、        Unicode发展历史
字符必须经过编码以后才能被计算机处理,计算机使用的默认编码方式称为计算机的内码。早期的计算机使用7位的ASCII编码作为内码,但ASCII编码只能处理2^7=128个字符(包括英文字母、数字、符号、控制字符等),但是世界上有着成百上千种的语言,仅仅用ASCII是无法进行处理的。因此,世界各国开始纷纷研究处理本国语言的方法。在中国为了处理汉字,程序员设计了用于简体中文的GB2312编码和用于繁体中文的big5编码。
 
中国各种编码标准的情况:
1980年公布的GB2312编码标准一共收录了7445个字符,包括6763个汉字和682个其它符号。
GB2312 支持的汉字太少。1995年公布的汉字扩展规范GBK1.0则收录了21886个符号,它分为汉字区和图形符号区,汉字区包括21003个字符。
     2000年发布的GB18030正式取代GBK1.0成为国家标准,该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字,所以现在的PC平台必须支持GB18030标准。
 
 
光是在中国就有那么多种不同的编码方式,世界各国编码方式的混乱情况就可想而知了。于是人们开始寻求一种统一的标准编码方法来表示和处理世界上绝大多的语言,众多的编码方法中最后只有Unicode编码最终成为了事实标准。
Unicode字符集编码是(Universal Multiple-Octet Coded Character Set) 通用多八位编码字符集的简称,支持世界上超过650种语言的国际字符集。它是由一个名为 Unicode 协会(Unicode Consortium)的机构制订的字符编码系统,支持现今世界各种不同语言的书面文本的交换、处理及显示。该编码于1990年开始研发,1994年正式公布,最新版本是2005年3月31日的Unicode 4.1.0,Unicode协会的官方网站是http://www.unicode.org,上面有关于Unicode的最新消息与最权威的资料。
 
二、        Unicode编码术语解释
UCSUniversal Multiple-Octet Coded Character Set(通用多八位编码字符集)的字符集,也可以以看作是"Unicode Character Set"的缩写。有UCS-2和UCS-4两种不同的实现方法,UCS-2采用两个字节进行编码,而UCS-4采用4个字节(实际上只用了31位,最高位必须为0)进行编码。
UTF编码:UCS Transformation Format(UCS转换格式),它是将Unicode编码规则和计算机的实际编码对应起来的一个规则,用于网络传输、编码转换等。
Little Endian/Big Endian:字节序,也就是处理多字节时采用的顺序,例如:“南”字的Unicode编码是5357,字节序将决定它写到文件里时,是53在前还是57在前,如果是Big Endian则写为5357,反之则是5753。
 
三、        Unicode编码中的数学
1、 UCS-2使用2个字节,即16位来编码,所以共可以表示216=65536个码元;UCS-4使用4个字节,即32位来编码,但最高位必须为0,所以共可以表示231=2147483648个码元。
2、UCS-4码元的管理:由于UCS-4表示的码元非常大,所以需要采用一种机制来管理这些码元。UCS-4先根据最高字节不同分为27=128个群组,再根据第二个字节不同分为28=256个平面,然后根据第三个字节不同分为28=256行,最后根据第四个字节不同分为每行分为256个单元。也就是说同一行的不同单元只是最后一个字节不同,其余都相同。
3、UCS-4编码中,群号为0,平面号为0的所有码元称之为BMP,即Basic Multilingual Plane(基础多语言平面)。
4、将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。
这些数据和关系可以由下图清楚的得到:

 
 
群号: 0~127
 
 
平面号: 0~255
 
 
行号: 0~255
 
 
单元号: 0~255
 


0
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
 
UCS4-编码示意图
 
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
UCS-4 BMP编码示意图
 

x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x

UCS-2编码示意图
 
 
四、        Unicode编码的问题及解决方法
Unicode里,所有的字符被一视同仁。像拆字、统计字数这些问题也就很容易解决。但是,也不可能在一夜之间所有的系统都使用Unicode来处理字符,所以Unicode从一开始,就必须考虑一个问题:和ASCII字符集之间的不兼容问题。比如字符“A”的ASCII码是65,而它的Unicode码则是0065,这就造成了一个非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了。另一个更加严重的问题就是,C语言使用'/0'作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉,这明显不可能做到。
事实证明,对可以用ASCII表示的字符使用UNICODE并不高效,因为UNICODE比ASCII占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处。为了解决这个问题,就出现了一些介于ASCII和UNICODE中间格式的字符集,但他们本质也是UNICODE编码。他们被称为通用转换格式,即UTF(Universal Transformation Format)。它不像Unicode码一样只停留在理论基础上,它是真实地存在于计算机中的。
 
五、        UTF相关知识
目前存在的UFT系列编码标准有:UTF-7、UTF-7.5、UTF-8、UTF-16、UTF32五种,UTF-8和UTF16比较常用,下面分别介绍:
UTF-8:它是UNICODE的一种变长字符编码标准,现在已经标准化为RFC 3629。使用1到6个字节来编码UNICODE字符。UTF-8里英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。下面的表是它与Unicode编码之间的对应关系,接下来的算法也会用到。
 
Unicode
UTF-8
00000000 - 0000007F
0xxxxxxx 
00000080 - 000007FF
110xxxxx 10xxxxxx 
00000800 - 0000FFFF
1110xxxx 10xxxxxx 10xxxxxx 
00010000 - 001FFFFF
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
00200000 - 03FFFFFF
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
04000000 - 7FFFFFFF
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
后面三个范围段里的Unicode编码,目前尚未使用到,所以一般不予考虑。这个表也称为字节模板,用于UTF-8与Unicode之间的转换.转换方法就是先确定编码所需要的字节数,然后用UNICODE编码二进制位从低位到高位依次填入上面表示为x的位上,不足的高位以0补充。举例说明:汉字“码”的Unicode编码十六进制为0x7801,落在第三个范围内,所以要用3个字节来表示,把0x7801转换为二进制111100000000001;按照字节模板写成:111 100000 000001的形式,然后用字节模板填充为:11100111 10100000 10000001,再转化为十六进制就得到了“码”的UTF-8编码为E7A081。这样以字节为编码单元,没有字节序的问题。
UTF-16:以16位为单元对Unicode进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于≥ 0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的必然小于0x10000,所以就目前而言,可以认为UTF -16和UCS-2基本相同,如果不加特别说明,UTF-16基本上可以等同于Unicode和UCS-2。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题,Unicode规范中推荐的标记字节顺序的方法是BOM(Byte Order Mark):字节序标识符。
Unicode编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE",而这个字符按照上述算法转换到UTF-8得到的是EF BB BF。这样如果接收者收到FEFF,就表明这个字节流是BigEndian的;如果收到FFFE,就表明这个字节流是LittleEndian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM,而如果接收到以EF BB BF开头的字节流,则说明这个字节流是用UTF-8来编码的。
 
2006-03-06补充关于代理对(Surrogate Pair)的相关内容:
为了发展,Unicode在BMP定义了一个代理区(Surrogate Zone)(D800至DFFF), 并将这个区域平分为前后两个各容纳1024(1K)个编码的区域(D800-DBFF及DC00-DFFF),分别称作高半代理(High Surrogate)及低半代理(Low Surrogate)区域。从这两个区域分别各取一个编码,分别称为高半代理键(High Surrogate Key)及低半代理键(Low Surrogate Key),由这两个Key组合成一个4字节代理对(Surrogate Pair)来表示一个编码字符。由于这两个区域内并没有定义任何的字符或符号,而且只有将这两个代理对(Surrogate Pair)结合在一起才能表示一个字符,单独使用其中的任何一个都没有意义。所以一个现有的应用程序无论何时遇到输入来自此两块保留区的任何一个编码时,它都是没意义的。
Surrogate机制可对应到一百万个字符(1024x1024=1,048,576),这一百万个字符分别对应到ISO 10646 中00组的00至0F这16个字面(plane),每一个字面的容量为64K(256x256),CJK扩展集B,位于第二个字面(plane 2),第14, 15个字面(plane 15, 16)则留做用户自定义区域(user private area)。  

关于更多字符编码等问题可以参阅《the unicode standard》等相关资料,这里我另附上两篇参考文档.

http://www.aspxuexi.com/vbscript/2007-2-12/2103.htm

http://www.cnblogs.com/sw22225458/archive/2008/01/15/1040132

原创粉丝点击