iOS - Unicode编码

一、来历

 

为了统一编码,各大龙头企业就决定坐下来对全世界的字符进行编码,并且尽量兼容现有字符集,这就有了unicode编码。Unicode用了21个二进制位,能够编码一百多万个字符,但实际上并没有编码这么多。U+XXXX中XXXX就是码点,就是字符在unicode的数字表示。

编码空间被分成 17 个平面(plane),每个平面有 65,536 个字符。0 号平面叫做「基本多文种平面」(Basic Multilingual Plane, BMP),涵盖了几乎所有你能遇到的字符,除了 emoji。其它平面叫做补充平面,大多是空的。

 

二、UTF-32、UTF-16、UTF-8

 

什么字符被表示成什么样子的规定有了,就要考虑怎么存起来了,这就分成了UTF-32、UTF-16、UTF-8三种了。所以UTF-32、UTF-16、UTF-8只是unicode的三种实现方式。

 

三、UTF-32

 

unicode用了21位,那我就用4个字节存,准错不了,这就是UTF-32,由于它的极度浪费,所以基本上没人用。

 

四、UTF-16

 

UTF-16编码介于UTF-32与UTF-8之间,同时结合了定长和变长两种编码方法的特点。UTF-16把字符存储成2个字节或者4个字节。

具体如下:
基本平面的字符占用2个字节,辅助平面的字符占用4个字节。也就是说,UTF-16的编码长度要么是2个字节(U+0000到U+FFFF),要么是4个字节(U+010000到U+10FFFF)。

于是就有一个问题,当我们遇到两个字节,怎么看出它本身是一个字符,还是需要跟其他两个字节放在一起解读?

说来很巧妙,我也不知道是不是故意的设计,在基本平面内,从U+D800到U+DFFF是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。

具体来说,辅助平面的字符位共有2的20次方个,也就是说,对应这些字符至少需要20个二进制位。UTF-16将这20位拆成两半,前10位映射在U+D800到U+DBFF(空间大小210),称为高位(H),后10位映射在U+DC00到U+DFFF(空间大小210),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。

 

五、相当巧妙的UTF-8

 

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

UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

 

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


举例说明:
已知\"严\"的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此\"严\"的UTF-8编码需要三个字节,即格式是\"1110xxxx 10xxxxxx 10xxxxxx\"。然后,从\"严\"的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,\"严\"的UTF-8编码是\"11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

由于大学学习离散数学时有一种变长的编码方式,受其影响太大,对于UTF-8的编码方式一度觉得不可思议,现在来看原来如此~

 

六、UTF-16的大头、小头问题

 

Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做\"零宽度非换行空格\"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

但是为什么要分大头和小头呢?

UTF-8编码单位为字节,并且多节字的编码也规定了他们的顺序(低字节和高字节),因此在储存和传输过程不会出现问题;

但UTF-16就不同,它以16位整数、双字节作为编码单位,规定了多个(两个)双字节编码的顺序(高位双字节和低位双字节),但对于每个双字节在储存和传输中,这两个字节谁先谁后的问题。如果不作相关规定,在小头机器中,把会双字节中的低字节储存(或传输)在前面,高字节在后;大头机器则相反,会造成混乱和错误。

其实这个我也不明白,但是跟机器底层相关的就不想研究啦~如果大学学得好的应该能懂哒~可惜我忘了,只有个模糊的概念。

 

posted @ 2016-10-31 14:42  小Garfield  阅读(2294)  评论(0编辑  收藏  举报