ASCII
我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0
和1
两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000
到11111111
。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码(全称是“美国信息交换标准码”,American Standard Code for Information Interchange),一直沿用至今。
ASCII 码一共规定了128个字符的编码,比如空格SPACE
是32(二进制00100000
),大写的字母A
是65(二进制01000001
)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0
。
但这仅适用于英文字母、数字和一部分符号,世界上还有许多语言的字符需要能够被计算机系统处理,这样就需要一个比ASCII
大得多的字符集囊括这些字符。
Unicode
就是用来解决这些问题的。
GB2312
GB2312 编码,就是在 ASCII 编码的基础上进行扩充的,它规定如下:
ASCII 的字符完整地包含在GB2312里,编码不变,仍然是以0开头,用一个字节来表示一个字符;对于ASCII没有的字符,就用1开头来区分,用两个字节合起来表示一个字符。
这样,在解码的时候,遇到字节是以0开头的,就知道这一个字节就表示了一个字符;遇到字节是以1开头的,就知道要加上下一个字节合起来表示一个字符。这样就在 GB2312 中既把ASCII的字符包含了进来,又能将它们区分出来,能达到兼容的效果了
GBK 即汉字内码扩展规范,其中 K 为汉语拼音扩展中扩字的声母。共收入 21886 个汉字和图形符号。
Unicode
这是全世界最大的字符集,相对于ASCII码,Unicode大大扩展了编码位数到16 - 32位,意味着它理论上最多可以容纳 2 32 ≈ 42 亿 2^{32}≈42亿 232≈42亿 个字符。Unicode包含了各种字母、中日韩文字、emoji等几乎所有语言和领域的符号,如汉字“我”对应的Unicode是01100010 00010001,写成16进制就是6211。现在互联网上传递、展示所使用的编码基本都是Unicode。它的最低7位与ASCII码是完全兼容的,即如果用16位Unicode来表示大写字母A,就会写成00000000 01000001。
Unicode 的问题
需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
有两个严重的问题:
- 怎么才能知道一个字节表示一个符号,而不是三个字节表示
- 如果统一用三个字节表示一个符号,那么英文字符必然存在浪费
UTF-8
UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8 的编码规则很简单,只有二条:
- 对于单字节的符号,字节的第一位设为
0
,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。 - 对于
n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则
Unicode符号范围 | UTF-8编码方式 |
---|---|
(十六进制) | (二进制) |
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
总结
- ANSI:文件的编码就是两个字节
D1 CF
,这正是严
的 GB2312 编码,这也暗示 GB2312 是采用大头方式存储的。 - Unicode:编码是四个字节
FF FE 25 4E
,其中FF FE
表明是小头方式存储,真正的编码是4E 25
。 - Unicode big endian:编码是四个字节
FE FF 4E 25
,其中FE FF
表明是大头方式存储。 - UTF-8:编码是六个字节
EF BB BF E4 B8 A5
,前三个字节EF BB BF
表示这是UTF-8编码,后三个E4B8A5
就是严
的具体编码,它的存储顺序与编码顺序是一致的。
**简单来说:**Unicode、GBK和Big5码等就是编码的值(也就是术语“字符集”),而UTF-8、UTF-16、UTF32之类就是这个值的表现形式(即术语“编码格式”)。
**另外:**Unicode、GBK和Big5码等字符集是不兼容的,同一个汉字在这三个字符集里的码值是完全不一样的。如"汉"的Unicode值与gbk就是不一样的,假设Unicode为a040,GBK为b030。以UTF-8为例,UTF-8码完全只针对Unicode来组织的,如果GBK要转UTF-8必须先转Unicode码,再转UTF-8就OK了。
即GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
- GBK、GB2312 --先转–> Unicode --再转–> UTF8
- UTF8 --先转–> Unicode --再转–> GBK、GB2312
参考文章
- 字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8 - 知乎 (zhihu.com)
- ASCII、Unicode、UTF-8、GBK的区别与联系_ascii unicode utf-8 gbk区别-CSDN博客
- 字符编码笔记:ASCII,Unicode 和 UTF-8 - 阮一峰的网络日志 (ruanyifeng.com)
- 【编码】彻底弄懂ASCII、Unicode、UTF-8之间的关系 - 大唐西域都护 - 博客园 (cnblogs.com)
- 一文看懂字符编码 - Unicode、UTF8、GBK、GB2312、ANSI和ASCII - 兔子先生wt - 博客园 (cnblogs.com)