HOME

关于字符编码

很早之前就碰到过”乱码”这个现象,当时非常困惑,完全不能理解发生了什么。

上大学以后,虽然开始接触计算机,不过我就没看到过具体讲解字符编码的内容。对这个领域始终是感到非常模糊。

不过,最近好像豁然开朗了一下,感觉突然就明白了这个问题。

下面我来解释一下我所理解的字符编码。

首先,所有的字符(或者说所有的信息)都是以二进制的形式存储在计算机中。所谓的编码就是映射字符与相应的二进制之间的规则。这样的映射可以任意定义,只要大家都遵守就行了。

比如非常经典的ASCII码,就将英文中的字符映射为一个字节。比如,A这个字符编码为65,存储在计算机中为01000001,占据一个字节。

其他的所有字符编码都是同理,比如汉字的经典编码GBK。

以我的名字举例,丁这个汉字,GBK编码为B6A1,存储为二进制是10110110 10100001(直接将B6A1换成二进制),两个字节。

用shell查看内部字节可以看出,如图:

同样的道理,如果使用utf-8编码,丁在unicode字符集中的编号为0x4E01,但它存储在计算机中并不是简单的将0x4E01翻译为对应的二进制。

这里就要分清楚两个概念,字符集和字符编码。字符集是定义字符的,每一个字符在字符集中都有一个唯一的编号,Unicode就是一个字符集,丁这个字符在Unicode字符集的编号是0x4E01。

字符编码是指将字符编号变换成二进制的方法。一个字符编号,有很多种方式可以存储在计算机中。例如,我想存储编号10,我可以存储为二进制的20,每次在计算机中取得数字后除以二就得到了我的编号。至于为什么要这么干,大多是出于兼容性和方便解码的考虑。

理解了这两个概念的不同,就能明白utf-8,utf-16的区别,他们都指的是Unicode字符集,但是代表的是不同的编码方法,同样的一个Unicode字符,经utf-8编码产生的二进制和utf-16编码产生的不一样。

utf-8的编码机制不算很复杂,wiki里说的很清楚,这里就不在赘述了。

现在来说说为什么要有乱码。

当计算机打开一个文本文件的时候,他必须要知道这个是什么编码的。否则无法解码,因为在计算机眼中,一切都是二进制字节流。但是不同的编码下相同的字节有不同的含义。同样是0xABCD,在某一个编码下可能表示“丁“,在另一个编码下可能表示的就是“王”了。

打开文本文件的时候,如果不手动指定编码,大部分程序都会自动推测编码(怎么推测是另外一个话题了)。如果计算机推测的编码或者用户手动指定的编码和实际编码不符,那么自然就会出现“乱码”现象,也就是内容看上去乱七八糟,实际上在计算机看来,只是用特定的编码方式解码字符而已,只不过解码出来的字符不是你想要的。