【编码】彻底弄懂ASCII、Unicode、UTF-8之间的关系

时间:2021-07-05 05:13:21

计算机中的所有字符,说到底都是用二进制的0、1的排列组合来表示的,因此就需要有一个规范,来枚举规定每个字符对应哪个0、1的排列组合,这样的规范就是字符集

ASCII

全称是“美国信息交换标准码”(American Standard Code for Information Interchange),制定于20世纪60年代,这套规范规定了128个字符对应的二进制码。128=27,即只需要7个bit就能完全表示,因此每个ASCII码只需占用1个字节(1Byte = 8bit)。

例如,大写字母A对应ASCII编码是01000001。点击查看完整的ASCII码表

假如一个文本文件存放了100个ASCII编码的字符,那么这个文件内容的大小就是100B。

ASCII规范只涵盖了英文字母、数字和一部分符号(包括换行符、制表符等控制性符号),但世界上还有许多语言的字符需要能够被计算机系统处理(比如几万个汉字),这样一来就需要制定一个比ASCII大得多的字符集,足够把全世界所有字符都囊括进去。这个字符集就是Unicode。

Unicode

这是全世界最大的字符集,相对于ASCII码,Unicode大大扩展了编码位数到16 - 32位,意味着它理论上最多可以容纳 232≈42亿 个字符。Unicode包含了各种字母、中日韩文字、emoji等几乎所有语言和领域的符号,如汉字“我”对应的Unicode是01100010 00010001,写成16进制就是6211。现在互联网上传递、展示所使用的编码基本都是Unicode。它的最低7位与ASCII码是完全兼容的,即如果用16位Unicode来表示大写字母A,就会写成00000000 01000001。

UTF-8

Unicode覆盖面很广,但如果一定要用16乃至32位来存储和传输每个符号,对于主要使用ASCII码的西方用户,势必会出现大量仅仅用于补位的0位,造成硬件资源浪费。为此,人们发明了UFT-8编码,使用可变的位数来表示Unicode里的字符。

UTF-8是怎么做的呢?

1.  对于单字节就可表示的字符,第一位为0,后面7位为该字符的ASCII码

2. 对于需要≥2个字节才可表示的字符,第一个字节以1开头,且该字符总共占了几个字节,就插入几个连续的1;连续的1结束后,插入一个0。后续字节全部以01开头。

如下表所示(表格来自阮一峰老师的博客

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

将“我”编码成UTF-8的操作方法如下:
“我”的Unicode码是6211,对应表里3字节编码的区间。在Unicode二进制码相应位置插入控制位,得到
11100110 10001000 10010001
写成16进制就是E68891,这样就得到了UTF-8编码。

当然,对于一般的开发者来说,编码细节是次要的,只要知道是怎么一回事就行了~

所以,当一个HTML页面被添加了<meta charset="utf-8">标签时,计算机就知道,每当这个页面文本的字节流里发现一个E68891,就应该把它视为“我”字。但假如页面编码时不是遵循的UTF-8,而是GB2132(它和UTF-8毫无关系),那么就会出现乱码——计算机错误解读了这些字节的意思。