计算机编码方式--为什么总是乱码?

在平时的文件处理过程中,有时会发现打开后的文件内容与预期不符,是一堆看不懂的符号,这主要是因为文件存储时选择的编码方式与文件打开时选择的编码方式不一样。由于大部分编码方式并没有一个唯一标识,这也造成了文本处理工具无法自动识别编码方式。接下来详细介绍一下常见的几种编码方式

ASCII

世界上第一台计算机诞生于美国,底层都采用二进制存储。由于美国就26个英文字母,加上一些数字和符号,总共也没多少字符,所以当时就设计了ASCII(American Standard Code for Information Interchange,美国信息交换标准码),仅仅只需要一个字节,使用0-127,每一个数字表示一个字符,总共128个字符,这样每一个字符都能编码成一个数字,以二进制的形式进行存储。常见的如数字1的编码为49,字母“a”的编码为97,字母“A”的编码为65。

计算机编码方式--为什么总是乱码?

GB2312 & GBK & GB18030

随着计算机在全世界的普及,很多国家都不使用英文,他们的文字在ASCII中是找不到的,所以他们使用128-255这127个数字来表示新的字符,叫做“扩展字符集”

等到了中国使用计算机的时候,不包括各种少数民族的文字,单单常用汉字就有6763个,一个字节已经远远诠释不了上下五千年的悠久文化了。所以中国国家标准局基于ASCII设计了GB2312(信息交换用汉字编码字符集),全部使用两个字节表示,共收入汉字6763个和非汉字图形字符682个,其中对于ASCII中的128个字符保持不变,在前面添加一个字节的0。并且对127及以下的符号、数字、英文字母都使用两个字节重新编码,叫做“全角”字符,而原来ASCII中的128个字符叫做“半角”字符。GB2312高位字节仅使用0xA1-0xF7范围,低位字节使用0xA1-0xFE。

GBK编码基于GB2312,新增了近20000个汉字,GBK仅要求高位字节大于127,对低位字节不做限制。

GB18030基于GBK,增加了几千个少数民族的文字。

ANSI编码就是英文使用ASCII编码,中文使用GB2312编码

Unicode

而随着各个国家都基于ASCII进行不同的扩展,导致同样的编码在不同的国家表示不同的字符,互相都无法解析。ISO(International Organization for Standardization,国际标准化组织)主导设计了Unicode字符集,请注意Unicode仅仅是一种字符集,而不是编码方式。

Unicode学名为Universal Multiple-Octet Coded Character Set,简称USC,俗称才是Unicode,USC可以看作是"Unicode Character Set"的缩写。Unicode规定了符号的二进制代码,但是并没有规定如何存储,所以基于Unicode,又产生了各种不同的编码方式。

UTF-8

UTF,Unicode Transformation Format:Unicode码转换格式。UTF-8是Unicode的一种实现方式,可以用1-4个字节表示一个字符,是一种变长的编码方式,使用变长的编码方式主要是在尽量多的覆盖不同字符的情况下,减小存储空间。(虽然可以对每一个字符都使用4个字节进行编码,但同时也意味着存储空间的巨大浪费)

变长编码方式带来的问题是,假设有3个字节,无法确定这3个字节是表示3个字符,还是表示1个字符,所以对UTF-8做了一些特殊的编码规则:

  1. 对于单个字节的字符,最高位设为0,后面7位为这个字符的Unicode码,与ASCII相同
  2. 对于n(n>1)字节字符,第一个字节的前n位都设置为1,第n+1位设置为0,后面字节的的前两位一律设置为10,其余未说明的为这个字符的Unicode码
UTF-8编码方式
Unicode码(十六进制) UTF-8编码(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

 

例如“你”的Unicode码是 “4f 60”,属于0800 - FFFF的范围内,二进制表示为01001111 01100000,对应的UTF-8则是11100100 10111101 10100000,使用十六进制表示则是“e4 bd a0”。

UTF-16

UTF-16也是一种变长的编码方式,使用2个或4个字节表示一个字符,包括BMP和16个辅助平面。

BMP(Basic Multilingual Plane,基本多文种平面),USC-4根据最高位为0的最高位字节分为2^7=128个group,次高位2^8=256个plane,每个plane根据第三个字节分为256行(rows),每行包括256个cells。其中group=0并且plane=0的被称作BMP。

平面划分:

  1. 0 - FFFF的为BMP
  2. 10000 - 1FFFFD的空间称作第一辅助平面(Supplementary Multilingual Plane, 简称SMP),摆放拼音文字(主要为现时已不再使用的文字)及符号
  3. 20000 - 2FFFFD,第二辅助平面,又称表意文字补充平面(Supplementary Ideographic Plane, 简称SIP)
  4. 30000-3FFFD,第三辅助平面,又称表意文字第三平面 (Tertiary Ideographic Plane, 简称TIP)
  5. ...

UTF-16由于使用两个字节为基本单位,所以存在字节序的问题。例如“你”的Unicode码是 “4f 60”,那么应该存储为“4f 60”,还是“60 4f”呢?

Unicode中推荐的标记字符序的方式是BOM(Byte Order Mark,字节序标志)。在Unicode编码中,有一个叫做“ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。在传输文本字节之前,建议先传输字符“ZERO WIDTH NO-BREAK SPACE”,如果接收者收到的是FEFF,则代表的是Big-Endian(“你”应该存储为“4f 60”),如果收到的是FFFE,则表达是Little-Endian(“你”存储为“60 4f”)。由于UTF-8是单字节的,所以不存在字节序的问题,规定可以用BOM来表示编码方式,“EF BB BF”则表示是UTF-8编码。

UTF-32

UTF-32规定所有字符均使用4个字节存储,这种编码方式在日常使用中比较少见,因为不再BMP的字符都不常用。