文字编码指南
是否被ASCII,GB2312,GBK,Unicode,UTF-8,UTF-16,UTF-32这些编码搞得“欲仙欲死”?让我们来彻底理解它们!!
“开天”之ASCII
计算机最早通用编码方案是ASCII。采用7位来表示128个字符,它被称为标准ASCII编码。后来还做了扩展,用8位来表示256个字符,叫做ASCII扩展编码。

“百花齐放”之ANSI
ANSI美国国家标准协会。每个国家制定自己的编码规则都需要得到ANSI的认可,每个国家或地区的各自编码都可以叫做ANSI编码。我们比较常见的ANSI编码有中国的GB2312,台湾的BIG5。还有一个GBK是微软自己的搞出来的编码,完全兼容GB2312,所以常常可以混淆。
ANSI的标准是什么呢?就是完全兼容ASCII,所以不能占用ASCII的编码范围,其他自己扩展。比如GB2312的编码是从0xA1A1
到0xFEFE
,可表示23901个汉字,实际才7000多个,GBK则从0x8140
到0xFEFE
,可表示3万多汉字。
不过ANSI有个巨大的缺陷,它不能同时显示不在同一个字符集中的文字,比如不能同时显示阿拉伯文和中文。所以我们需要一个字符集,上面包含了所有国家的字符。
“大一统”之Unicode
基于ASNI的缺陷,Unicode万国码呼之而出。它是一张包含世界上所有文字的编码表。
Unicode的编码范围为0x000000-0x10FFFF,可以容纳1114112个字符。Unicode字符用4个字节来表示,一共有32位,其中最高位为0,接着的7位将Unicode分成了128个Group,再接着的8位将Unicode分成了256个Plane(平面)。而Unicode只使用17个平面,每个平面都有65536个字符,平面的具体划分如下:
平面 | 编码范围 | 用途 |
---|---|---|
0 | 0000-FFFF | 基于多文种平面 |
1 | 10000-1FFFF | 多文种补充平面 |
2 | 20000-2FFFF | 表意文字补充平面 |
3 | 30000-3FFFF | 表意文字第三平面 |
4-13 | 40000-DFFFF | 尚未使用 |
14 | E0000-EFFFF | 特殊用途补充平面 |
15 | F0000-FFFFF | 保留作为私人使用 |
16 | 100000-10FFFF | 保留作为私人使用,emoji所在平面 |
Unicode只是编码表,如何存储到计算机中还需要设计存储方案,我们常见的实现方案有UTF-8,UTF-16,UTF-32。
- UTF-8 Unicode编码4个字节太长了,UTF-8对其进行了可变长处理,编码规则如下:
Unicode编码 | UTF-8编码模板 |
---|---|
000000 - 00007F | 0xxx xxxx |
000080 - 0007FF | 110x xxxx 10xx xxxx |
000800 - 00FFFF | 1110 xxxx 10xx xxxx 10xx xxxx |
010000 - 10FFFF | 1110 0xxx 10xx xxxx 10xx xxxx 10xx xxxx |
我们来举个例子,“汉”的Unicode码为0x6C49
,在0x0800-0xFFFF
之间,使用1110 xxxx 10xx xxxx 10xx xxxx
,而0x6C49
的二进制数为0110 1100 0100 1001
,将这个二进制替换x,则UTF-8最终存到计算机中的编码为1110 0110 1011 0001 1000 1001
-
UTF-16 UTF-16的编码规则如下(记某一编码为U): 当
U<0x10000
时,只有两个字节,UTF-16的存到计算机中的编码和Unicode编码值一致。 当U>=0x10000
时,u=U-0x10000
得到的值最多20位(10FFFF-0x1000=FFFFF
),所以将u
的二进制填进1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
这个模板,得到最终值,所以有4个字节。我们看到很多两个字节表示的unicode码都是UTF-16,例如\uD842\uDFB7
就是UTF-16编码的。 -
UTF-32 UTF-32很简单,和Unicode编码一一对应,规定为4个字节
emoji 编码问题: emoji现在十分流行,在IOS5之前,emoji是使用Softbank的编码版本,在IOS5之后,使用了Unicode定义的emoji字符,编码范围为1F600-1F64F。在UTF-8中,其存储为4字节,所以有的时候MySQL在插入emoji符号时会出错,因为MySQL的utf8编码只能插入3字节的,我们只要改MySQL的编码成utf8mb4就好。我们在网页中可以使用UBB编码显示emoji编码。IOS和Android显示emoji是不同的,因为Android没有采用Unicode定义的emoji。