机器码
我们知道计算机最终识别的信息都是二进制值,每一个二进制位(bit)有0和1两种状态,所有语言的编码最终都会转化为二进制的机器码才能被计算机识别。
ASCII
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。
ASCII 码一共规定了128个字符的编码,总共占用了八个二进制位,称为一个bit(字节);
但其实英文字符以及符号只占用了7个二进制位,最前一位统一为0。
ISO-8859-1
ASCII码对于英语系国家是够用的,对于部分欧洲国家128个字符就不够用了,于是ISO组织决定利用最高位,扩展为256个字符,这也是国际标准。
GB2312
ASCII码以及ISO的编码,可以基本适用于一些西方国家的语言,但用来标识中文就相形见绌了,一个字节是不够的,必须使用多个字节标识一个字符,GB2312就是使用两个字节标识一个字符,所以理论上最多可以表示 256 x 256 = 65536 个符号。
GBK
GB2312几乎能包含中国大陆99.75%的中文,但有些生僻字还是没有录入,GBK是对于GB2312的扩展,因此完全兼容GB2312,收录一些生僻字和图形符号。
Unicode
以上几种编码都是通过1个或多个字节表示,是不同地区和国家对于ASCII码的扩展。
但是在全球互联时代,这时候由于各自编码标准都不一样,彼此之间都是乱码,无法良好的沟通交流,这时候统一的UniCode标准就出现了。UniCode是一个很大的字符集,记录着世界上所有字符对应的一个数字,以十六进制表示。
但是Unicode只是字符集,并不等同于编码方式,因为它二进制代码的储存,我们知道英文通常只占用一个字节,而中文则占用多个字节,这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?
我们知道现在Unicode最大字符有4个字节表示,可以用最大字节数表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,这显然是无法接受的。
于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。
UTF-8
UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。
UTF-8 的编码规则很简单,只有二条:
对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
不过UTF-8标识中文基本上都需要3个字节,相比于GB类的会更占用空间,但考虑到它的适用性(针对英文又有天然的优势-单字节)
UTF-16
Unicode编码中,最常用的字符其实是0-65535,因此针对这点产生了UTF-16方案。
UTF-16将0–65535范围内的字符编码成2个字节,超过这个的用4个字节编码。(因此基本可以认为是双字节的)
UTF16编码是Unicode最直接的实现方式,通常我们在windows上新建文本文件后保存为Unicode编码,其实就是保存为UTF16编码。
总结
对中文字符后面四种编码格式都能处理,GB2312 与 GBK 编码规则类似,但是 GBK 范围更大,它能处理所有汉字字符,所以 GB2312 与 GBK 比较应该选择 GBK。
UTF-16 与 UTF-8 都是处理 Unicode 编码,它们的编码规则不太相同,相对来说 UTF-16 编码效率最高,字符到字节相互转换更简单,进行字符串操作也更好。它适合在本地磁盘和内存之间使用,可以进行字符和字节之间快速切换,如 Java 的内存编码就是采用 UTF-16 编码。
但是它不适合在网络之间传输,因为网络传输容易损坏字节流,一旦字节流损坏将很难恢复,想比较而言 UTF-8 更适合网络传输,对 ASCII 字符采用单字节存储,另外单个字符损坏也不会影响后面其它字符,在编码效率上介于 GBK 和 UTF-16 之间,所以 UTF-8 在编码效率上和编码安全性上做了平衡,是理想的中文编码方式。