Unicode字符集的UTF-32、UTF-16和UTF-8编码
什么是Unicode字符集?简单地说,它就是把全世界人类发明和使用的现有的所有字符进行了集中收集和逐一编码,这个过程就像把上学时老师把班里学生都叫到一起,统计总数后给每个学生分配一个唯一的学号一样。Unicode字符集里收录的字符可以是文字(如:‘α’、‘魍’等),也可以是符号(如:‘@’、‘$’),还可以是图形(如'☺'等)。
那它有什么用呢?它有两个重要的用途:
一是解决了人们和机器之间的字符交互问题。每个字符不再是一个个抽象的文字、符号或图形,而是变成了一个个的数字,每个数字对应一个唯一的字符,而每个字符也有一个唯一的数字,两者之间是一一对应关系,而且不同字符和不同数字都各不相同,避免了“重名重姓”问题。这里,提到的表示字符的数字,我们也称之为 码点 ,后面我们还会详细介绍。
二是解决了不用语言国家字符集编码不统一的问题,提供了一个统一的编码方式,避免“各自为政,政出多门”的问题,方便相互之间的数据交流。
有了基本概念,那么我们看看Unicode字符集是如何实现对所有字符编码的。根据官网公布的Unicode 最新版本(9.0)介绍,Unicode字符集现在共包括 128,172 个字符,可查看 http://www.unicode.org/versions/Unicode9.0.0/ 。如此大量的字符,该如何编码?最笨的办法就是把所有字符列出来,然后一个一个编个号,但这样不利于查找,也不利于分类,更不利于进行存储空间优化编码(后面会介绍一些优化编码方案)。
那Unicode字符集怎么解决这个编码问题呢?它采用的是“分块编码”。按照国籍、地区、用途、功能等不同属性,把字符先进行分类,然后再根据每个小字符类的字符个数,确定一个个大小不同的 码块 ,下面节选了几种字符及其对应的 码点 。
(节选)
0000..007F; Basic Latin(基本拉丁字母)
4E00..9FFF; CJK Unified Ideographs(CJK统一表意文字)
1D100..1D1FF; Musical Symbols(音乐符号)
100000..10FFFF; Supplementary Private Use Area-B(补充专用区域-B)
注意,“0000”、“007F”、“1D100”以及“100000”等,都是十六进制,这是每个字符在Unicode字符集中的编号,也就是相当于每个字符的“学号”。
可以看出,要表示一个字符,最长需要6位十六进制数,换算一下就是24位二进制数;而短的,比如基本拉丁字母,前面的“0”省去,只要2位十六进制(8位二进制数)就行了。
有了字符集,下面就要谈谈如何表示和使用这些字符(码点)了。毕竟,谁也不会闲了没事把字符编个号就为了练自己认字和数数的能力。 最重要的当然是为了让不同信息受体间交换信息 。
于是,就出现了UTF。所谓UTF是Unicode Transformation Format的缩写,意为Unicode转换格式。UTF具体分为3类,分别是UTF-32,UTF-16和UTF-8。
先看UTF-32。UTF-32是 定长编码 ,也就是说每个字符的编码长度都是固定的,‘32‘是其所使用的二进制编码的位数,即: 32位 。但通常以字节数进行量化,所以32位对应的字节数为 4字节 。
我们的Unicode字符集每个字符的码点最长也就是24位,相当于3个字节,而UTF-32给了4个字节(32位)来表示,给了字符集非常大的扩展空间(有兴趣的童鞋可以算算32位二进制数最大可以表示多大的数,这个数基本就对应了可以表示多少字符)。
没这时间计算这些的童鞋你就简单理解为,UTF-32就是一个“运超大箱”的快递公司,不管你寄什么,它都统一拿装冰箱的盒子寄(觉得不够大的,自行脑补一个),保证能一次装下你要寄的东西。
它的优点是被表示的Unicode字符都是固定长度的,易于查找和解码;但缺点是表示常用字符时内存占用太大,本地存储利用率或传输效率太低。
UTF-16是 变长编码 ,也就是说每个字符的编码长度是变化的,不是一成不变的。它的编码算法为:
在UTF-16中,2字节是字符的基本表示单元,低码点的用 2字节 表示,高码点的拆开后用 2个2字节 表示。
还是拿快递公司的例子类比,UTF-16是家提供了一种“运中等箱子”的快递公司,中等箱子能装下的就直接寄,装不下的,做个标记,分两个箱子寄,收件人需要特别注意下标记,如果没有标记,直接就用,如果有,就把两个箱子东西取出来拼起来后再用。
UTF-8也是 变长编码 ,它的编码算法与UTF-16并无本质区别,都是对Unicode进行分段,然后加上标识码,唯一的区别是分段更多。其算法如下:
在UTF-8中,1字节是字符的基本表示单元,最低的码点( 000000-0000FF )用1字节表示,高的码点( 000080-10FFFF )进一步分段,分别拆开为2个、3个和4个1字节。
可见,相比较而言,UTF-8是家只能“运小箱子”的快递公司,少数能装下的就用1个箱子运,不能装下的就拿2个、3个甚至4个来运。作为收件人,会非常辛苦的进行逐一判别,基本上都是需要拆箱组装后才能使用的(下面讲到也会有特例)。
当然,UTF-8在对于拉丁语系国家或者字符为主的信息传递和数据处理时,效率是非常高的,因为刚才Unicode字符集节选中提到的基本拉丁语范围刚好是 0000..007F ,在UTF-8中只要1个字节就够了。但是,对于中日韩(CJK,China-Japan-Korea)语系或字符为主的信息传递和数据处理时,效率就不那么好了,因为刚才节选的中日韩表意文字范围是 4E00..9FFF ,那在UTF-8中进行编解码时必须按照上面UTF-8算法的 第3条 进行处理,也就是要用 3个字节 来表示(还不如UTF-16的 2字节 ),所以国内很多中文数据较多的网站一般也不会采用UTF-8来进行编码,但作为程序猿还是比较喜欢用这种的编码方式。
完。