Skip to content

ASCII码

计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有01两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。
一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000011111111

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码(American Standard Code for Information Interchange,美国信息交换标准代码),一直沿用至今。

ASCII 码一共规定了128个字符的编码,每一个都对应一个7位(bits)的二进制数,最前面的一位统一规定为0
包含:控制字符(0-31, 127)数字(32-47)大写字母(65-90):A-Z小写字母(97-122):a-z标点符号

非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0-127表示的符号是一样的,不一样的只是128-255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如:

  • GB2312:中国国家标准总局于1980年颁布的一套用于信息交换的汉字编码字符集,适用于汉字处理、汉字通信等系统之间的信息交换。‌,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。
  • GBK:1995年颁布,与GB2312兼容,是GB2312的修订方案,能够表示更多的汉字和其他字符(支持更多的中、日、韩(CJK)汉字)。
  • GB18030:使用4字节编码,兼容ASCII、GB2312、GBK。包括2000年编制的GB18030-2000,2005年编制的GB18030-2005。
  • Big5:多用于台湾香港等地,主要是收录了繁体字。在包含汉字数量上来说,Big5是GBK的子集,但是二者的编码方式是不同的。

Unicode

世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。
有一种编码,将世界上所有的符号都纳入其中,每一个符号都给予一个独一无二的编码,这就是 Unicode,其规模可以容纳100多万个符号。

  • Unicode编码由16进制数字表示,前面加上U+,例如U+0041表示英语的大写字母A(0041转为10进制为65,与ascii编码中值相同)。
  • Unicode字符集被划分为 17 个平面(即,17个区,编号为 0-16 ),每个区有2^16个代码点,因此Unicode字符集共有17 × 65536 = 111 4112 个码点。
  • 整个Unicode字符集的码点空间为U+000000 ~ U+10FFFF
  • 具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。 比如,汉字的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:
1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。
2)Unicode 在很长一段时间内无法推广,直到互联网的出现。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。规则如下:

  1. 对于单字节的符号,字节的第1位设为0后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于n字节的符号(n > 1),第1个字节的前n位都设为1第n+1位设为0后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
Unicode范围(十六进制)utf-8编码方式(二进制)字节数
0000 0000-0000 007F0xxxxxxx1
0000 0080-0000 07FF110xxxxx 10xxxxxx2
0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx3
0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx4

即:如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100`100 10`111000 10`100101,转换成十六进制就是E4B8A5

Little endian 和 Big endian

字严为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,
4E在前,25在后,这就是 Big endian 方式;
25在前,4E在后,这是 Little endian 方式。
那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做零宽度非换行空格(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1

  • 如果一个文本文件的头两个字节是FE FF,就表示该文件采用Big endian;
  • 如果头两个字节是FF FE,就表示该文件采用Little endian。

Unicode编码中表示字节排列顺序的那个文件头,叫做BOM(byte-order mark),FFFE和FEFF就是不同的BOM。
UTF-8文件的BOM是EF BB BF,但是UTF-8的字节顺序是不变的,因此这个文件头实际上不起作用。有一些编程语言是ISO-8859-1编码,所以如果用UTF-8针对这些语言编程序,就必须去掉BOM,即保存成“UTF-8—无BOM”的格式才可以,PHP语言就是这样。

ascii编码对照表

十进制二进制字符描述十进制二进制字符描述
000000000NUL空字符6501000001A大写字母A
100000001SOH标题开始6601000010B大写字母B
200000010STX正文开始6701000011C大写字母C
300000011ETX正文结束6801000100D大写字母D
400000100EOT传输结束6901000101E大写字母E
500000101ENQ请求7001000110F大写字母F
600000110ACK确认7101000111G大写字母G
700000111BEL响铃7201001000H大写字母H
800001000BS退格7301001001I大写字母I
900001001TAB水平制表7401001010J大写字母J
1000001010LF换行7501001011K大写字母K
1100001011VT垂直制表7601001100L大写字母L
1200001100FF换页7701001101M大写字母M
1300001101CR回车7801001110N大写字母N
1400001110SO移出7901001111O大写字母O
1500001111SI移入8001010000P大写字母P
1600010000DLE数据链路转义8101010001Q大写字母Q
1700010001DC1设备控制18201010010R大写字母R
1800010010DC2设备控制28301010011S大写字母S
1900010011DC3设备控制38401010100T大写字母T
2000010100DC4设备控制48501010101U大写字母U
2100010101NAK否定确认8601010110V大写字母V
2200010110SYN同步空闲8701010111W大写字母W
2300010111ETB传输块结束8801011000X大写字母X
2400011000CAN取消8901011001Y大写字母Y
2500011001EM媒介结束9001011010Z大写字母Z
2600011010SUB替补9101011011[左方括号
2700011011ESC转义9201011100\反斜杠
2800011100FS文件分隔符9301011101]右方括号
2900011101GS组分隔符9401011110^插入符号
3000011110RS记录分隔符9501011111_下划线
3100011111US单元分隔符9601100000`反引号
3200100000SPACE空格9701100001a小写字母a
3300100001!感叹号9801100010b小写字母b
3400100010"引号9901100011c小写字母c
3500100011#井号10001100100d小写字母d
3600100100$美元符10101100101e小写字母e
3700100101%百分号10201100110f小写字母f
3800100110&和符10301100111g小写字母g
3900100111'单引号10401101000h小写字母h
4000101000(左括号10501101001i小写字母i
4100101001)右括号10601101010j小写字母j
4200101010*星号10701101011k小写字母k
4300101011+加号10801101100l小写字母l
4400101100,逗号10901101101m小写字母m
4500101101-减号11001101110n小写字母n
4600101110.句号11101101111o小写字母o
4700101111/斜杠11201110000p小写字母p
48001100000数字011301110001q小写字母q
49001100011数字111401110010r小写字母r
50001100102数字211501110011s小写字母s
51001100113数字311601110100t小写字母t
52001101004数字411701110101u小写字母u
53001101015数字511801110110v小写字母v
54001101106数字611901110111w小写字母w
55001101117数字712001111000x小写字母x
56001110008数字812101111001y小写字母y
57001110019数字912201111010z小写字母z
5800111010:冒号12301111011{左大括号
5900111011;分号12401111100|竖线
6000111100<小于号12501111101}右大括号
6100111101=等号12601111110~波浪号
6200111110>大于号12701111111DEL删除
6300111111?问号
6401000000@电子邮件符号

参考链接