阿瑞斯的BLOG

字符集和字符编码

首先,在了解字符集和字符编码是什么之前先去看看为什么会有字符集和字符编码,它是为了解决什么问题?

字符集的产生

我们平时在计算机屏幕上看到的文字内容并不是直接以文字的形式存储在计算机的存储介质中,计算机存储介质中存放的实际上是二进制的比特流。也就是说,不论你在计算机上看到的汉字,英文字母,日文等等,一旦存入计算机存储介质中,最终都是以010101010形式存放。那么如何确保拿出来转换的是汉字不是日文呢?显然,在这两者之间的转换就需要一个统一的规则,不然,当你把文档发给别人,别人的转换规则和你不一样,岂不是就出现乱码了?

所以为了统一转换,字符集就诞生了。简单的说,字符集规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(解码)的转换关系。

“字符集”就像谍战片中的“译码本”一样,发电报时,大家发送的都是”滴答滴答”的原始信息,但是通过译码本,就可以转换成真实的字符。就像译码本一样,同样的原始信息经过不同的译码本翻译可能得到不同的结果;对于相同的一个字经过不同的译码本转换,翻译出的内容也不一样,这也就是为什么谍战片中大家都这么重视译码本。

对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。

  • 字库表

    是一个相当于所有可读或者可现实字符的数据库,字库表决定了整个字符集能够展示的所有字符的范围。

  • 编码字符集

    即用一个编码值code point来表示一个字符在字库中的位置。

  • 字符编码

    将编码字符集和实际存储数值之间的转换关系。一般来说都会直接将code point的值作为编码后的值直接存储(ASCII中)

这么看来,字库表和编码字符集看来是必不可少的,既然字库表已经有序号了那为什么不直接把序号作为存储内容呢?干嘛还要多此一举通过字符编码把序号转换成另一种存储格式呢?

因为统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用的过程中呢,真正用到的字符占字库表的比例是非常低的。比如老美,他们仅仅可能仅仅只用到了ASCII中的128个字符,但是如果都以字库表中的序号来存储的话,原本ASCII中的一个字符只占一个字节,现在一个字符占了三个字节,这显然对他们很不友好。这个时候就出现了UTF-8这样的变成编码。在UTF-8编码中,原本只占一个字节的ASCII字符,仍然只占一个字节。

为什么会有Unicode字符集编码标准?

因为ASCII是美国人自己用的,ASCII开始普及之后,各国针对ASCII字符不够自己国家/地区使用,在ASCII上做了扩展,因为此,出现了同一个二进制编码表示不同编码的问题。解决了一个字节不够表示全球中所有符号的问题。

UTF-8和Unicode的关系

Unicode就是字符集编码,而UTF-8就是字符编码,就是Unicode规则字库的一种实现形式。unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到UTF-8并不是直接的对应,而是要过一些算法和规则来转换。UTF-8编码的实现方法,即UTF-8的物理存储和Unicode序号的转换关系。

为什么会出现乱码?

编码和解码时使用了不同的字符集。对于字符”很屌”经过UTF-8编码后,它的十六进制表示E5BE88E5B18C这串数字,而我们显示的时候用GBK解码进行展示。(GBK的解码规则是:对于一个字节,如果它是小于127的,那么它就是一个英文单字节。而如果某个字节是大于127,就表示是一个汉字的开始.所以当时会有1个汉字2个英文字符的说法),此时GBK会把这串数字拆成 E5BE 88E5 B18C三组,每组两个字节,所以GBK解码后就成了寰堝睂三个字符。不仅和原来的完全不一样还多了一个。

出现乱码后如何识别原来的想要表达文字?

  1. 编码(发现乱码的当前编码,转回二进制)
  2. 切割(获取二进制字符串并按字节拆成字节数组)
  3. 解码

最后补充一下计算机中存的是二进制,但是常见的用十六进制表示而不用十进制?或者其他八进制?

因为二进制过长的数字代码对于阅读带来不便,十进制和二进制没有指数型关系。十六进制简洁且和二进制成倍数关系,两个十六进制就可以表示8个二进制位也就是一个字节。