编码

计算机底层保存的数据都是 0 1 这样的二进制数据,如果要成为能读懂的内容,那么这肯定涉及到一个映射的关系,即 0110 0010 这个字节代表什么东西,这个东西,可以是一个字符,可以是一个字符串,可以是一个数字。

在计算机里面,二进制的数据表示一个字符,这样的技术就叫做“字符编码”

ASCII 编码

ASCII 编码,上世纪 60 年代,美国制定的一套字符编码,对英文字符和二进制数据表示之间做了关系的映射。一共 128 个字符,对应的 16 进制数 0x00 - 0x7F,二进制表示即 0000 0000 - 0111 1111

例如:0x20,代表空格字符,二进制表示即 0010 0000,十进制为 32

其他语言,其他编码

ASCII 编码可以满足英文的需要,即一个字节 8 位就可以表示英文用到的所有字符,但是其他语言就未必够了,因为 8 位最多只能表示 2^8=256 个东西(字符)

例如汉字,多达 10 万以上,一个字节肯定不够。一个字节肯定不够,因此就有了其他编码方式的产生:比如GB2312,使用两个字节表示一个汉字,那么理论上,就可以表示 2^8 * 2^8 = 256 * 256 = 65536 个汉字

Unicode

那 Unicode 又是什么?

由于编码方式的不同,同样的一个二进制数据,它在不同的编码方式下可以表示不同的字符

这也解释了有时候收到别人的发你的文件是乱码的原因,因为创建编辑这个文件的时候使用的编码和你打开的时候使用的编码不一样,虽然底层二进制数据都是一样的

那么这个问题怎么破,简单的方式就是一套编码可以表示所有的字符,那么 Unicode 就是这套编码,它里面的每一个编码都是唯一表示一个字符,可以是表示一个英文字符, 也可以是表示一个中文字符

比如:U+4100 表示“一”,U+2661 表示一个爱心符号

Unicode 存在的问题

Unicode 虽然能将所有的东西都数字化,所有的东西都可以表示为二进制的数字,但是,说到底它只是一个字符集合。

它引入的新问题就是:

  • 由于存储方式的不确定,同样的一串 2 进制数字,如何区别它是 Unicode 还是 ASCII。假设,空格,ASCII 表示 0x20,存储为 0010 0000,那么为了区别开来,Unicode 存储可能就会存为 0000 0010,当然这里只是举个例子
  • 每个东西都能唯一表示后,英文字符只要一个字节就够了,汉字也许两个字节也够了,但是随着内容的加入,后期可能会用三个字节,四个字节来表示一个东西,但由于统一编码,之前的东西也应该拥有相同的字节数,只不过高位的字节都是 0

导致的结果:Unicode 存储方式无法统一,文件内容变得很大

UTF-8

为满足互联网统一编码的需要,UTF-8 出现了。UTF-8 是互联网里最常使用的一种 Unicode 实现方式。

注意:UTF-8 只是其中一种实现方式,还有 UTF-16,UTF-32,但是 UTF-8 使用最普遍

UTF-8 特点:1-4 个字节,长度可变的编码方式。可变意味空间利用率的提高,但是也意味着计算成本的增加。简单的说,有的符号一个字节,有的要三或四个字节才能表示

编码规则

  1. 单字节的符号,字节第一位为 0,后面 7 位为这个符号 Unicode 码,对于英文来说,这其实兼容了 ASCII 码
  2. 对于 n 个字节符号,n > 1,第一个字节的前 n 位都是 1(几个 1 就是几个字节),n + 1 位为 0,后面 n - 1 个字节的前两位都是 10。其余剩下的二进制位提供给这个符号的 Unicode 码使用
字节数 固定格式
1 0xxxxxxx
2 110xxxxx 10xxxxxx
3 1110xxxx 10xxxxxx 10xxxxxx
4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

编码转换参考:

Utf-8 固定格式(二进制) Unicode 表达式范围(十六进制)
0xxxxxxx 00000000 - 0000007F(二进制 7 个 1)
110xxxxx 10xxxxxx 00000080 - 000007FF(二进制 11 个 1)
1110xxxx 10xxxxxx 10xxxxxx 00000800 - 0000FFFF(二进制 16 个 1)
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 00010000 - 001FFFFF(二进制 21 个 1)

Unicode “ʊ”,U+028A,介于 00000080 - 000007FF,Unicode 二进制表示为 0000 0010 1000 1010

转为 Utf-8 二进制表示为 11001010 10001010(十六进制:CA 8A)

Unicode “䂤”,U+40A4,介于 00000800 - 0000FFFF,Unicode 二进制表示为 0100 0000 1010 0100

转为 Utf-8 二进制表示为 11100100 10000010 10100100(十六进制:E4 82 A4)