1. unicode与iso 10646
全世界很多个国家都在为自己的文字编码,并且互不想通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码euc-kr中“”的编码值正好是汉字编码gbk中的“”)。因此,同一份文档,拷贝至不同语言的机器,就可能成了乱码,于是人们就想:我们能不能定义一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了。
如果说“各个国家都在为自己文字独立编码”是百家争鸣,那么“建立世界统一的字符编码”则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构试图来做这个事:
(1) ,他们于1984年创建iso/iec jtc1/sc2/wg2工作组,试图制定一份“通用字符集”(universal character set,简称ucs),并最终制定了标准。
(2) ,他们由xerox、apple等软件制造商于1988年组成,并且开发了标准(the unicode standard,这个前缀uni很牛逼哦---unique, universal, and uniform)。
1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从unicode 2.0开始,unicode采用了与iso 10646-1相同的字库和字码;iso也承诺,iso 10646将不会替超出u 10ffff的ucs-4编码赋值,以使得两者保持一致。两个项目仍都独立存在,并独立地公布各自的标准。不过由于unicode这一名字比较好记,因而它使用更为广泛。
unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point)。17个平面的码位可表示为从u xx0000到u xxffff,其中xx表示十六进制值从0016到1016,共计17个平面。
2. utf-32与ucs-4
在unicode与iso 10646合并之前,iso 10646标准为“通用字符集”(ucs)定义了一种31位的编码形式(即ucs-4),其编码固定占用4个字节,编码空间为0x00000000~0x7fffffff(可以编码20多亿个字符)。
ucs-4有20多亿个编码空间,但实际使用范围并不超过0x10ffff,并且为了兼容unicode标准,iso也承诺将不会为超出0x10ffff的ucs-4编码赋值。由此utf-32编码被提出来了,它的编码值与ucs-4相同,只不过其编码空间被限定在了0~0x10ffff之间。因此也可以说:utf-32是ucs-4的一个子集。
3. utf-16与ucs-2
除了ucs-4,iso 10646标准为“通用字符集”(ucs)定义了一种16位的编码形式(即ucs-2),其编码固定占用2个字节,它包含65536个编码空间(可以为全世界最常用的63k字符编码,为了兼容unicode,0xd800-0xdfff之间的码位未使用)。例:“汉”的ucs-2编码为6c49。
但俩个字节并不足以正真地“一统江湖”(a fixed-width 2-byte encoding could not encode enough characters to be truly universal),于是utf-16诞生了,与ucs-2一样,它使用两个字节为全世界最常用的63k字符编码,不同的是,它使用4个字节对不常用的字符进行编码。utf-16属于变长编码。
前面提到过:unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point),而第一个平面称为“基本多语言平面”(basic multilingual plane,简称bmp),其余平面称为“辅助平面”(supplementary planes)。其中“基本多语言平面”(0~0xffff)中0xd800~0xdfff之间的码位作为保留,未使用。ucs-2只能编码“基本多语言平面”中的字符,此时utf-16与ucs-2的编码一样(都直接使用unicode的码位作为编码值),例:“”在unicode中的码位为,而在utf-16编码也为6c49。另外,utf-16还可以利用保留下来的0xd800-0xdfff区段的码位来对“辅助平面”的字符的码位进行编码,因此utf-16可以为unicode中所有的字符编码。
utf-16中如何对“辅助平面”进行编码呢?
unicode的码位区间为0~0x10ffff,除“基本多语言平面”外,还剩0xfffff个码位(并且其值都大于或等于0x10000)。对于“辅助平面”内的字符来说,如果用它们在unicode中码位值减去0x10000,则可以得到一个0~0xfffff的区间(该区间中的任意值都可以用一个20-bits的数字表示)。该数字的前10位(bits)加上0xd800,就得到utf-16四字节编码中的前两个字节;该数字的后10位(bits)加上0xdc00,就得到utf-16四字节编码中的后两个字节。例如:
(这个字念啥?^_^)
上面这个汉字的unicode码位值为2aeab,减去0x10000得到1aeab(二进制值为0001 1010 1110 1010 1011),前10位加上d800得到d86b,后10位加上dc00得到deab。于是该字的utf-16编码值为(该值为大端表示,小端为)。
4. utf-8
从前述内容可以看出:无论是utf-16/32还是ucs-2/4,一个字符都需要多个字节来编码,这对那些英语国家来说多浪费带宽啊!(尤其在网速本来就不快的那个年代。。。)由此,utf-8产生了。在utf-8编码中,ascii码中的字符还是ascii码的值,只需要一个字节表示,其余的字符需要2字节、3字节或4字节来表示。
utf-8的编码规则:
(1) 对于ascii码中的符号,使用单字节编码,其编码值与ascii值相同(详见:)。其中ascii值的范围为0~0x7f,所有编码的二进制值中第一位为0(这个正好可以用来区分单字节编码和多字节编码)。
(2) 其它字符用多个字节来编码(假设用n个字节),多字节编码需满足:第一个字节的前n位都为1,第n 1位为0,后面n-1 个字节的前两位都为10,这n个字节中其余位全部用来存储unicode中的码位值。
字节数 | unicode | utf-8编码 |
---|---|---|
1 | 000000-00007f | 0xxxxxxx |
2 | 000080-0007ff | 110xxxxx 10xxxxxx |
3 | 000800-00ffff | 1110xxxx 10xxxxxx 10xxxxxx |
4 | 010000-10ffff | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
5. 总结
(1) 简单地说:unicode属于字符集,不属于编码,utf-8、utf-16等是针对unicode字符集的编码。
(2) utf-8、utf-16、utf-32、ucs-2、ucs-4对比:
对比 | utf-8 | utf-16 | utf-32 | ucs-2 | ucs-4 |
---|---|---|---|---|---|
编码空间 | 0-10ffff | 0-10ffff | 0-10ffff | 0-ffff | 0-7fffffff |
最少编码字节数 | 1 | 2 | 4 | 2 | 4 |
最多编码字节数 | 4 | 4 | 4 | 2 | 4 |
是否依赖字节序 | 否 | 是 | 是 | 是 | 是 |
参考: