常用编码学习
常用编码
在计算机世界,所有信息都是用二进制存储。每一个二进制有0和1两种状态。
所以8个二进制就可以组合成256种状态,也就是一个字节。
也就是说,一个字节可以用来表示256种不同的状态,每一个状态对应一个符号,也就是256个符号,从00000000—11111111。
ASCII码
一共规定了128个字符的编码,包含大小写字母、数字、还有空格等一些常用符号,这128个符号中有32个不能打印出来的控制符号。只占用了一个字节的后面7位,也就是最前面一位都是0.
大写字母A是65,也就是二进制的01000001。
空格是32,也就是二进制的00100000。
非ASCII编码
上面讲的ASCII编码规定的128个字符,对英语来说足够用了,但是用来表示其他语言,128个符号不够用。例如,法语字母上面有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。
比如,法语的é的编码为130,二进制位10000010,这样以来欧洲国家可以使用8个二进制的所有组合,也就是最多256个符号。
但是,这也有问题,130在法语编码中表示é,而在希伯来语编码中却代表字母Gimel(ג),在俄语编码中又代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是不一样的,不一样的只是128—255的这一段。
至于亚洲国家的文字,额….汉字就10W+,256种符号肯定不够,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用256个字节表示一个汉字,所以理论上最多表示256*256=65536个符号。
当然,世界上的编码方式有很多,不止上面提到的这些。
Unicode
世界上存在着多种编码方式,同一个二进制数字可以被解释不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。
Unicode是一种把世界上所有符号都纳入其中,每一个符号都给予了一个独一无二的编码,那么乱码问题就会消失。
Unicode是一个很大的集合,现在的规模可以容纳100多万个符号,每个符号的编码都不一样,比如:
U+0639表示阿拉伯字母Ain。
U+0041表示英语的大写字母A
U+4E25 表示汉字严
Unicode的问题
Unicode只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
例如:汉字严转化为二进制是100111000100101,足足有15位,也就是最少需要两个字节,甚至有更大的符号,需要3个字节或者4个字节,甚至更多。
这就有了两个严重的问题:
1.如何区分Unicode和ASCII,计算机怎么知道三个字节表示一个符号,而不是表示三个符号呢?
2.我们已经知道英文字母只用一个字节表示就足够了,如果Unicode同一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必须有2—3个字节是0,这对于数据存储来说是极大的浪费,文本文件的大小因此会打出2—3倍,这是无法接受的。
UTF-8闪亮登场
UTF-8是Unicode的一种实现方式,其他实现方式还有UTF-16(字符用2—4个字节表示),UTF-32(字符用四个字节表示),不过其他的在互联网上基本不用,UTF-8就是为了统一编码方式产生的,也是互联网上使用最广的一种Unicode的实现方式。
UTF-8的最大特点,就是它是一种边长的编码方式,可以使用1—4个字节来表示一个符号,根据不同的符号而变化字节长度。
它的规则很简单,只有两条:
对于单字节的符号,字节的第一位为0,后面7位为这个符号的Unicode码。因此,对于英文字母,UTF-8和ASCII码是相同的。
对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律为10。
汉字严的Unicode是4E25(100111000100101),需要用三个字节存储,根据上面的规则,即格式为:
1110xxxx 10xxxxxx 10xxxxxx
记住,二进制是从后往前存储的,读也是从后往前读的,所以我们先填充第三个字节,从二进制的后面读取,填充完后变成了:
1110xxxx 10xxxxxx 10100101
再根据同样规则填充第二个字节,填充完后变成了:
1110xxxx 10111000 10100101
最后填充最后一个字节:
1110x100 10111000 10100101
不对啊,怎么少了一个字节?没事,少了的用0补位:
11100100 10111000 10100101
Unicode与UTF-8的转换
这两种编码的转换可以通过程序实现,在Windows平台下,最简单的方法是,通过记事本另存为:
ACSI就是ACSII,是Windows英文系统的默认的编码格式,但是对于Windows简体中文版默认就是GB2312,针对繁体中文版默认就是Big5。
而现显示的Unicode都是使用UCS-2编码方式存储的Unicode字节,只不过默认是little endian格式,而另一个选项是Unicode big endian格式。
Unicode little endian与Unicode big endian的转换:
简单举个例子,UCS-2格式可以存储Unicode码。汉字严的Unicode码为4E25,需要用两个字节存储,一个字节是4E,另一个是25。4E在前,25在后就是Big endian(从前往后),25在前,4E在后,就是Little endian(从后往前)。
那计算机怎么知道某一个文件到底采用哪一种方式编码呢?
Unicode规范定义,每一个文件最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做 “zero width no-break space” ,用FEFF表示,正好是两个字节。
如果一个文本文件的头两个字节是FE FF,表示是Big endian方式,如果头两个字节是FF FE,表示是Little endian方式。
本文大部分来自阮一峰大神的个人博客:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html