ASCII 码
一个字节有8个bit, 对应的二进制从00000000到11111111, 我们可以理解为一个字节可以表示256个不同的状态。
ASCII码就是在上世纪60年代,由美国制定的一套字符编码(字符与二进制位的映射关系), 它可以用来标识128个字符(其中的33个是不可显示字符,剩余95个是可显示字符),如字母A的二进制是01000001,空格的二进制是00100000。这128个符号只占用了一个字节的后7位,最前面一位统一规定为0。
很显然ASCII码只能用于显示现代美国英语,但对更多其他语言依然无能为力。因此,现在软件系统大多采用Unicode。
Unicode
世界上存在很多编码方式,要打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。
如果有一种编码,可以把世界上所有编码纳入其中,为每个符号赋予独一无二的编码,那乱码问题就能消失了。这就是Unicode,正如它的名字表示的那样。Unicode目前可以容纳100多万个符号。比如U+0041表示A, U+79E6表示秦。
但是Unicode只是一个符号集, 它只规定了符号的二进制代码, 却没有规定这个二进制码应该如何存储。比如汉字秦的Unicode是十六进制79E6, 转换成二进制有15位(111100111100110), 也就是说这个符号表示至少需要2个字节。要表示其他符号,可能需要三个或更多字节。 这就导致计算机不知道几个字节标识一个符号。如果Unicode规定,用固定长度的字节来表示所有符号,那么那些明明只需要一个或两个字节就可以标识的符号必然有几个字节都是0, 就会极大的浪费存储空间,一个文本文件的大小可能会大出二三倍。
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 |
根据上面的编码规则,如果一个字节的第一位是0,则这个字节是单字节字符;如果第一位是1,有几个1就表示当前字符占几个字节。
以汉字“秦”为例来演示如何实现UTF-8编码。秦的Unicode编码是79E6(0111100111100110),按照上表,秦的UTF-8编码需要三个字节,即第三行的格式。然后,从秦Unicode的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。“秦”的UTF-8编码就是 11100111 10100111 10100110, 转换成十六进制就是E7A7A6。