首先,说一说Unicode字符集。计算机内存中数据都是01这样的二进制形式,但是对于人来说直接使用这样的二进制是非常不方便的。我们使用的是我们熟悉的字符例如’A’,’一’这样的字符。所以我们需要转换一下,这种转换是需要一种对照(映射)关系吧?字符集就可以看做是一种映射表。ASCII,GBK,Unicode字符集都可以看做是映射表。
当我们通过键盘(或其他输入设备),输入字符时,输入设备(或者响应的系统或者驱动)就会对其编码。例如我们使用ASCII编码当我们输入字符’A’的时候就会被编码为0x41(A的十六进制)存入内存中,计算机要做屏幕(或其他输出设备)上显示字符A就把0x41通过相应的驱动程序输出到屏幕,屏幕控制相应的设备(例如电子枪)打出A字符。
知道了大致的过程,我们接下来就来介绍一些Unicode字符集。因为每一个地方使用的字符时不一样的例如美国是用’a’这样的字符,中国使用’一’这样的字符,字符不一样,字符集当然也不一样。所以美国ASCII编码,中使用GBK,GB18030这样的编码。这样不一致,不说不能交流,但是交流肯定是不方便的。所以出来了一个Unicode组织,制定了一个Unicode字符集,基本可以照顾到各个国家的感受,大家都能使用它满足基本要求,这样有了共同语言(相同字符集)就好交流了。
Unicode字符集使用4字节的数字来表达每个字母、符号,或者表意文字。Unicode只是字符集,至于怎样对他进行编码,最常用的有3中方式,UTF-32编码方式,这种简单粗暴,直接使用4个字节(32位,Unicode字符集就是4个字节)来编码,所以也没有什么技巧和特殊处理,不用计算和检查什么。
另外一种是UTF-16,这种编码方式是使用2个字节(16位)来编码Unicode字符集。想一想啊,用2个字节来存放4个字节的东西,肯定需要一些特殊的技巧。UTF-16使用如下的表示方式:
如果字符编码U小于65535,则直接使用两字节表示;
如果字符编码U大于65536,由于UNICODE编码范围最大为1114111,从65536到1114111之间 共有1048575((2^20)-1)个编码,也就是需要20个bit就可以标示这些编码。用U'表示从1048575之间的值,将其前 10 bit作为高位和数值0xD800(16位)进行 逻辑or 操作,将后10 bit作为低位和0xDC00(16位)做逻辑or 操作,这样组成的 4个byte就构成了U的编码。
采用UTF-16这样的编码方式,空间效率显然得到了提升。但是人的创造力还是值得惊叹的,一些聪明的家伙又想出了UTF-8编码的方式,UTF-8是一种变长编码方式。它可以只使用1-6个字节来编码一个Unicode字符。Unicode字符才4个字节,UTF-8有可能是有6个字节,这样做真的有效率。事实上用5,6个字节来编码的还是很少的,UTF-8所以空间效率还是很好的,不然也不会被广泛使用。UTF-8的编码方式如下:
如果一个字符用一个字节编码,则最高位是0,其他位给出编码值(0到127);
如果一个字符用n(n>=2)个字节编码,则第一个字节的前n位为1,接着是一个0。随后的(n-1)个字节全部由“10”开头。所有字节的剩余位连接起来,形成了Unicode代码点值。由此可见:
(1)一个以0开头的字节表示单字节字符
(2)一个以11开头的字节表示一个多字节字符的开头
(3)一个以10开头的字节表示一个多字节字符的非开头
这样说可能有一点空洞,我们来一个实际的例子来看一看:
在Java中我们经常使用\u4E00-\u9FA5这样的方式来匹配中文汉字。因为Java使用的是Unicode字符集。\u4E00-\u9FA5这个范围就是Unicode字符集中的基本汉字的范围。下面我们以第一个汉字的Unicode字符\u4E00来介绍一下UTF-8怎样对Unicode字符编码。基本汉字在Unicode使用2有效的字节,所以UTF-8对基本汉字使用3个字节对其进行编码。
首先:把\u4E00转换成二进制:0100111000000000(注意不满16位高位补0)
按UTF-8的编码规则,3个字节的样式应该是:
111xxxxx
10xxxxxx
10xxxxxx
现在的问题关键是到底怎样填呢?从Unicode的低位开始按6为分开(因为如是多字节,除开第一个字节其他的都差6位),最高字节不知高位补0。
上面的\u4E00就被拆成了:
0100 111000 000000
我们先看高位0100只有4位和高字节的111组合只有7为还差一位,怎么办?高位补0,于是就变为11100100,其他2个字节也一样,所以最后变为下面的3个字节:
11100100 10111000 10000000(十六进制E4 B8 80)
你可以在编辑器中输入一个字符’一’,保存为UTF-8的格式。然后使用十六进制查看器打开,看到它的十六进制的编码为E4 B8 80,当然也可能是EF BB BF E4 B8 80这其中的EF BB BF是UTF-8的BOM(字节顺序标记(Byte Order Mark)。在Windows中的记事本会自动加上这3个字节。其他有些编辑器也可以指定加不加这3个字节,例如nodepad++就可以指定编码为以UTF-8无BOM的格式编码。