十分钟搞清字符集和字符编码(2)

为了更好的理解后面的实际应用,我们这里简单的介绍下UTF-8的编码实现方法。即UTF-8的物理存储和Unicode序号的转换关系。 UTF-8编码为变长编码。最小编码单位(code unit)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。

如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号。

如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后一个字节的除10外的部分(6个bit)代表在Unicode中的序号。且第二个字节以10开头

如果一个字节以1110开头,那么代表当前字符为三字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后两个字节的除10外的部分(12个bit)代表在Unicode中的序号。且第二、第三个字节以10开头

如果一个字节以10开头,那么代表当前字节为多字节字符的第二个字节。10之后的所有部分(6个bit)和之前的部分一同组成在Unicode中的序号。

具体每个字节的特征可见下表,其中x代表序号部分,把各个字节中的所有x部分拼接在一起就组成了在Unicode字库中的序号

Byte 1Byte 2Byte3
0xxx xxxx          
110x xxxx   10xx xxxx      
1110 xxxx   10xx xxxx   10xx xxxx  

我们分别看三个从一个字节到三个字节的UTF-8编码例子:

实际字符   在Unicode字库序号的十六进制   在Unicode字库序号的二进制   UTF-8编码后的二进制   UTF-8编码后的十六进制  
$   0024   010 0100   0010 0100   24  
¢   00A2   000 1010 0010   1100 0010 1010 0010   C2 A2  
  20AC   0010 0000 1010 1100   1110 0010 1000 0010 1010 1100   E2 82 AC  

细心的读者不难从以上的简单介绍中得出以下规律:

3个字节的UTF-8十六进制编码一定是以E开头的

2个字节的UTF-8十六进制编码一定是以C或D开头的

1个字节的UTF-8十六进制编码一定是以比8小的数字开头的

为什么会出现乱码

乱码也就是英文常说的mojibake(由日语的文字化け音译)。 简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。对应到真实生活中,就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。在计算机科学中一样,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。 我们来看一个例子:假设我们用UTF-8编码存储很屌两个字,会有如下转换:

字符UTF-8编码后的十六进制
  E5BE88  
  E5B18C  

于是我们得到了E5BE88E5B18C这么一串数值。而显示时我们用GBK解码进行展示,通过查表我们获得以下信息:

两个字节的十六进制数值GBK解码后对应的字符
E5BE    
88E5    
B18C    

解码后我们就得到了寰堝睂这么一个错误的结果,更要命的是连字符个数都变了。

如何识别乱码的本来想要表达的文字

要从乱码字符中反解出原来的正确文字需要对各个字符集编码规则有较为深刻的掌握。但是原理很简单,这里用最常见的UTF-8被错误用GBK展示时的乱码���例,来说明具体反解和识别过程。

第1步 编码

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13546.html