字符编码浅谈(二)

第三章 一统天下 – Unicode

1Unicode基础

我们还是先来看看维基百科上对Unicode是如何定义的:Unicode is a computing industry standard for the consistent encoding, representation and handling of text expressed in most of the world's writing systems

Unicode项目是由Unicode Consortium主导,目前最新版本是6.0Unicode目前包括109,000多个字符,包括一组可做为视觉参考的的代码图表,一套编码方法,上标和下标字,属性和规则等。从上面的介绍来看,Unicode其实并不是简简单单的一个字符集映射的问题,它其实包含了更多的东西,原因很简单:因为Unicode需要将这世界上所有的字符全部都包括进去,这绝对不是一项简单的工作。

具体来说,Unicode其实是一种抽象的编码系统,比如“孔”字在Unicode中编码为0x5B54Unicode其实是将0x5B54和“孔”字的内在含义关联了起来,二并不是将“孔”字的字形,即它是如何被书写的,关联起来,也就是与字体无关。也许这个例子并不是特别恰当,但是要将世界上所有的字符都进行编码,或许必须这么做。

另外,Unicode中还有一些控制字符,这些字符不能被打印出来,它们是来控制其他字符的输出的,比如控制字符斜体之类的(我没有找到例子,大家可以提供一些)。

Unicode包括编码方式和编码实现,比如将“孔”字编码为0x5B54是编码方式,UTF-8UTF-16等是Unicode的编码实现。UTF-8UTF-16将在随后介绍。

下面介绍两个Unicode术语:

第一个是:code point,即代码点。0x5B54就是个代码点,这个代码点被分配给“孔”,其实在这里就是一个整型数,可以被编码。

第二个是:BMPBasic Multilingual Plane ),即基本多语言平面,相对与补充平面。BMP其实是指一个代码点的范围。

下图显示了BMP的代码点范围(截图来自Unicode维基百科页面):

2UTF-8

大家可能对UTF-8很熟悉了,我来详细讲一下。UTF-8是最流行的Unicode实现,UTF-8意为:UCS Transfer Format-8UCS意为Universal Character Set 。所以,UTF-8其实是个字符编码传输格式。UTF-8为变长编码,从一个字节到最多4个字节(目前最多4个字节),汉字的UTF-8编码多为3个字节。

下面说一下UTF-8的编码规则,其实规则很简单,只有两个:

1)对于单字节的符号,字节的第一位设为0,后面 7位为这个符号的Unicode码。因此对于英语字母,

UTF-8编码和ASCII码是相同的。

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

UTF-8

举例:查表得“孔”字的Unicode编码为5B54

1,5B54在第三行,所以需要3个字节存储

2,5B54展开成二进制:0101101101010100,都按照从后往前的顺序, 填入空位(x标示),如果还有剩余空位,填写0。结果为E5AD94

3UTF-16

其实,对于Unicode实现,还有一个更简单的思路,就是直接用Unicode的编码来做为其实现,基于此则产生了UTF-16UTF-16编码是从00x10FFFF,包含了1,112,064个位置, 产生一个或者两个16位二进制的编码。

UTF-16的编码规则是:

BMP,直接采用代码点的标示 ;在BMP之外,产生多余116位二进制的编码。

对于UTF-16也有两种实现方法,即UTF-16的大端模式(UTF-16 BE)和小端模式(UTF-16 LE)。比如对于“孔”字的UTF-16编码为0x5B54,在传输时采用5B 54方式,则为大端模式,如果传输时采用 54 5B方式,则为小端模式。

如此一来,UTF-16就有两个非常明显的缺点:

1),不能编码所有的Unicode字符;

2),需要用BOMByte Order Mark)来标识传输时是采用大端模式还是小端模式。

4UTF-8的优点

1)ASCII编码不变,都为一个字节

2)可以编码所有的Unicode代码点

3)UTF-8编码字节流可以使用启发式算法识别,错误 率低

4)采用变长编码,效率较高(相对于UTF-16)

5)不用BOM(Windows下用记事本保存成UTF-8 格式,Windows会在文件头自动添加EF BB BF这三个 字节作为UTF-8BOM)

6)可扩展性好,从UTF-8的编码规则可以看出

第四章:一切都还没有结束 – 后记

有如此之多的编码方式,那么很容易提出这样的问题:如果没有说明使用什么方法编码,那么程 序如何检测编码方式? 其实,这个问题没有很好的答案(或许windows下的UTF-8编码前加“BOM”是个解决方法)。

由于上面提出的问题,也造成了一写“著名”事件:“联通”事件

1,在记事本中输入“联通”,默认采用GB系列的 编码

2,“联通”被编码为“C1AA CDA8”,转换成 二进制为“1100 0001 1010 1010 1100 1101 1010 1000”,正好和UTF-8的模式相同,所以 再次打开时模式使用UTF-8解码,编码结果是一个小黑方块,还有一个空格。

产生这个问题根源是 Windows API中的IsTextUnicode函数的bug,其他例 子还有Bush hid the facts等。

大家可能非常纳闷,为什么你写了这么多东西,还一直没有提到乱码这回事,嘿嘿,我这就说。我稍微总结了一下,产生乱码问题的根源很简单:编码方式和解码方式的不一致(只是个人见解总结),所以解决乱码问题的关键在于弄清除双方采用的编码方式。That's it.

最后,请大家记住一句话:There Ain‘t No Such Thing As Plain Text.

翻译过来就是:这世界上根本就没有“纯文本”。

所以,每当看到字符的时候,你就应该问问自己:它是用什么编码的?

致谢:

1)Wikipedia:很多词条我已经在文章中加上了链接, 在这里我就不一一列出了。

2)“There Ain't No Such Thing As Plain Text.” 句话来自http://www.joelonsoftware.com/articles/Unicode.html

3)http://www.laruence.com/2009/08/22/1059.html ,采用轻松的方式讲述了编码的发展历史。

4)http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html ,简述了Unicode UTF-8

5)感谢Unicode协会,他们是一群野心家,天才和疯子。http://www.unicode.org/ 

posted @ 2011-05-20 14:01  hit_alex  阅读(2138)  评论(6编辑  收藏  举报