略谈计算机编码
最近被问到 Unicode 和 UTF-8 的区别,于是就想起来了,之前也有人问过我这个问题,当时我也是一脸懵逼,于是就去查了一下,然后就忘了,现在又被问到了,于是就想着记录一下。
计算机底层存储都是存储的二进制的编码文件,计算机最初是由美国人发明的,于是他们制定了一组编码规则,其中包含了大小写的英文字母、数字、英文标点符号等,引发了计算机界的编码革命。
ASCII
ASCII(American Standard Code for Information Interchange),美国信息互换标准码。就是美国人最初发明计算机时制定的一组编码,是一种基于拉丁字母的编码,它只有 128 个字符,所以只需要 7 位就可以表示了,所以叫 7 位编码,编码为 0-127。
ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年
ISO-8859-1
由于 ASCII 只占用了 0-127 的范围,后来欧洲开始使用了计算机,于是在 ASCII 的基础上进行了扩展,扩展了 128-255 的范围,这就是 ISO-8859-1,它也是一种 8 位编码,向下兼容 ASCII。Latin1 是 ISO-8859-1 的别名,有些环境下写作 Latin-1,这是 MySQL 的默认编码。
1 | print(b'\xff'.decode('ISO-8859-1')) |
GB2312
后来中国也开始使用计算机,由于汉字的数量很多,ASCII 或 ISO-8859-1 是不够用的,于是就有了 GB2312
GB2312(国标2312) 是一种 16 位编码,也就是 2 个字节,GB2312 标准共收录 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;同时,GB2312 收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个全角字符。
GB2312 的编码规则是使用两个字节来表示一个汉字,其中两个字节均在 128-255 之间,这样进行编解码时,判断当前字节是否在0~127(ASCII码范围),如果在则表示当前为单字节的英文字母;否则会联合后面的一个字节共同判断当前的汉字表示
GBK
GB2312 并没有收录所有的汉字,而且 GB2312 的编码规则实际上浪费了一部分编码空间,例如当判断了第一个字节范围在 128-255 之间,就可以确定需要联合第二个字节进行解码,于是就有了 GBK
GBK(国标扩) 是 GB2312 的扩展,完全兼容 GB2312 ,共23940个码位,共收录了21003个汉字,
Unicode
由于出现了各种标准的编码,为了统一编码,于是就有了 Unicode
Unicode 是一种字符集,它包含了世界上所有的字符,它的编码范围是 0x0000 到 0x10FFFF,也就是 0 到 1,114,111,所以 Unicode 只是一个字符集,并不是一种在计算机中存储的编码方式
UTF-8
出现了 Unicode 字符集,但例如欧美国家实际上大部分的字符是用不到的,原本一个字节能表示的字符,现在需要用三个字符才能表示,这样就造成了空间的浪费,于是就有了 UTF-8
UTF-8(Unicode Transfer Format 8) 是 Unicode 的一种编码方式,它是一种变长的编码方式,它可以使用 1-4 个字节来表示一个字符,它的编码规则如下
字节 | 格式 | 实际编码位 | 编码范围 |
---|---|---|---|
1 | 0xxxxxxx | 7 | 0-127 |
2 | 110xxxxx 10xxxxxx | 11 | 128-2047 |
3 | 1110xxxx 10xxxxxx 10xxxxxx | 16 | 2048-65535 |
4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21 | 65536-2097151 |
UTF-16
UTF-16 是 Unicode 的一种编码方式,它是一种变长的编码方式,它可以使用 2-4 个字节来表示一个字符,它的编码规则如下,但是 UTF-16 有一个缺点,就是它不兼容 ASCII,也就是说,如果你的文本中只有英文,那么使用 UTF-16 编码的话,它会占用 2 倍的空间
字节 | 格式 | 实际编码位 | 编码范围 | 说明 |
---|---|---|---|---|
2 | xxxxxxxx xxxxxxxx | 16 | 0x000000-0x00ffff | 英文 汉字 日文 emoji 等 |
4 | 110110yy yyyyyyyy 110111xx xxxxxxxx | 20 | 0x010000-0x10ffff | 甲骨文等 |
UTF-32
UTF-32 是 Unicode 的一种编码方式,它是一种固定长度的编码方式,它使用 4 个字节来表示一个字符
字节 | 格式 | 实际编码位 | 编码范围 |
---|---|---|---|
4 | xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | 32 | 0-1114111 |
ANSI
ANSI 是 American National Standards Institute 的缩写,它是美国国家标准协会的意思,它是一个标准化组织,它制定了一些标准,其中就包括了 ANSI 编码
ANSI 在不同的国家标准不同,
ANSI 编码 | 国家标准 |
---|---|
GBK | 中国 |
BIG5 | 台湾 |
EUC-KR | 韩国 |
Shift_JIS | 日本 |
ISO-8859-1 | 欧洲 |
ASCII | 美国 |
BOM
BOM 是 Byte Order Mark 的缩写,它的编码是 FEFF ,它是一种标记,用来标记文件的编码格式,它是一个字节序列,它的作用是告诉解码器,当前文件的编码格式是什么,不同编码格式中的 BOM 值如下表
编码格式 | BOM 字节序列 |
---|---|
UTF-8 | EF BB BF |
UTF-16BE | FE FF |
UTF-16LE | FF FE |
UTF-32BE | 00 00 FE FF |
UTF-32LE | FF FE 00 00 |