在谍战剧中,我们经常会看到这样的情节,特工千辛万苦得到一条信息,打开看到一串数字,然后快速跑到一个秘密的地方,拿出一本密码本(可能是唐诗选集),然后按照一定的规则(只有我自己的人知道),比如第一个数字表示页数,第二个数字表示行数,第二个数字表示行数。三个数字代表前几个字,资料一一翻译。如果在这个过程中使用了错误的密码本,或者不知道规则,那么解码就会失败。计算机的编解码过程与上述过程相同。计算机只能识别0和1,所有的图像和字符最终都会被转换成计算机可以理解的二进制。一个二进制位(bit)可以表示0和1两种状态,而一个字节(byte)由八个二进制位组成,所以一个字节总共可以表示256(2^8)个状态。如果我们规定每个状态代表一个字符,那么一个字节可以表示256个字符。ASCII计算机是美国人发明的,所以当初设计编码时,只考虑英文编码。英文字符很少,加上一些特殊字符,总共只有100个左右,准确的说是128个。这样的话,用一个字节编码就完全够用了,不仅够用,而且还丰富了一个bit,也就是第一个bit没有参与编码,统一设置为0。这就是so-称为ASCII编码。在ASCII编码中,空格SPACE为32(二进制00100000),大写字母A为65(二进制01000001)。Non-ASCII随着计算机的普及,欧洲人也开始普及计算机。欧洲人发现ASCII规定的128个字符不能满足他们的需要。比如在法语中,如果字母上面有注音符号,就不能用ASCII码来表示。因此,一些欧洲国家决定将字节中的第一个空闲位编码成一个新的符号。例如,é在法语中的代码是130(二进制10000010)。这样,这些欧洲国家使用的编码系统最多可以表示256个符号。这就是大家经常看到的ISO-8859-1编码,也叫Latin1编码。中文编码随着电脑的普及,中国人也开始使用电脑,但是发现按照以前的编码方式,根本就没有汉字这个东西,也就是电脑根本看不懂汉字。GB2312为了让计算机能够识别汉字,我们决定对汉字进行编码。本着敢想敢做的精神,我们规定用两个字节表示一个汉字。具体规则如下:一个小于127的字节代表的意思和原来的ASCII相同,但是当两个大于127的字节连在一起时,就表示这是一个汉字,前一个字节称为高位字符节,下一个字节称为低字节,所以可以组合6763个简体字。这就是我们常说的GB2312编码。GBK显然有6763个GB2312编码的汉字,不能适应所有的使用场景。127就可以了,第二个字节大于127还是小于127都无所谓。经过这样的改动,收录的汉字和符号可以达到2W以上,也就是我们常说的GBK编码。后来人们继续扩展第二个字节,发展出了GB18030编码,比GBK多了一些字符编码。到目前为止,所有的汉字代码都是用两个字节来表示的,而英文是用一个字节来表示的。一些年龄段的程序员都体验过一个汉字相当于两个英文字符。上面提到的BIG-5代码是简体中文代码。GBK和GB18030虽然包含了一些繁体字,但并不全面,所以台湾同胞出台了专门支持繁体字的Big5编码,也就是大家常说的大五。代码。一个小问题。不知道大家有没有发现问题。在单字节编码的情况下,对于那些大于127和小于256的编码,不同国家代表的字母可能不同。例如,130在法语代码中代表é,但在希伯来语代码中代表字母Gimel(?),在俄语代码中代表另一个符号。汉字的双字节编码也存在这个问题。比如BIG5编码和GBK编码都是双字节编码,只是代表的汉字不同。这就相当于,对于同样的一串二进制值,A特工组织可以按照他们的规则解释为“Hello”,而B特工组织可以按照他们的规则解释为“滚出去”。特工组织之间有不同的翻译标准是必要的,但如果计算机的编码规则不同,那就更麻烦了。比如你和台湾的志玲姐姐聊天,志玲姐姐给你发一封信,用的是BIG5编码,然后你用GBK解码,……可能就没有了。为了解决以上问题,Unicode有一个国际标准组织叫ISO,决定放弃所有的区域编码,如BIG5、GBK等,重新制定新的编码。这套代码集会包含所有字符的编码,以便大家统一,这套代码的英文全称是“UniversalMultiple-OctetCodedCharacterSet”,简称UCS,俗称“Unicode”。Unicode的出现,相当于秦始皇统一了度量衡和货币。Unicdoe根据日常字符的使用频率划分了17个plane,编号为0-16,plane0称为BasicMultilingualPlane(BasicMultilingualPlane,简称BMP),包含日常生活中使用频率最高的字符,以及编码范围从0000到FFFF,这样这个平面就可以表示2^16=65536个字符;其他平面的编码范围也是从0000到FFFF,所以其他平面也可以编码65535个字符,所以17个平面总共可以编码17×65536=1114112个符号。我们最常用的Unicode编码采用的是多语言平面的编码,即所有的字符都用两个字节编码(其他平面可能需要三个或四个字节)。比如中国的字符'中'的Unicode编码是4E2D,小写'a'的Unicode编码是0061。这里有两个问题。如果所有的英文字符都按照Unicode编码,那么就会造成存储空间的浪费。.很明显,一个字节可以搞定,但它需要两个字节。第二个问题是计算机怎么知道是Unicode编码还是ASCII编码,即一个字符用2个字节表示,还是2个字符。UTFUTF的全称是UnicodeTransformationFormat,即Unicode的转换格式。上面说了,如果直接使用Unicode编码存储,会存在浪费空间的问题,而UTF-8的出现就是为了解决这个问题。UTF-8采用变长方式存储Unicode编码,即英文字符继续使用一个字节存储,但汉字使用3个字节。那么UTF-8是怎么做到的。首先,对于单字节符号,字节的第一位设置为0,后7位为符号的Unicode编码。所以对于英文字母,UTF-8编码和ASCII编码是一样的。其次,对于一个n字节的符号(n>1),第一个字节的前n位全部置1,第n+1位置0,后面字节的前两位全部置1到10。其余未提及的二进制位均为该符号的Unicode编码。下表总结了编码规则,字母x代表可用的编码位。Unicode符号范围(十六进制)UTF-8编码方式(二进制)00000000-0000007F0xxxxxxx00000080-000007FF110xxxxx10xxxxxx00000800-0000FFFF1110xxxx10xxxxxx10xxxxxx00010000-0010FFFF11110xxx10xxxxxx10xxxxxx10xxxxxx根据上表,如果对UTF-8编码进行解释,会发现如果一个字节的第一位是0,那么这个字节单独就是一个字符;多少字节。比如假设一个字符串“helloworld”,根据UTF-8的编码规则,它们的Unicode编码为1h--00682e--00653l--006C4l--006C5o--006F6世--4E167世界--754C可以得到如下UTF-8编码1h--011010002e--011001013l--011011004l--011011005o--011011116th--11100100-10111000-100101107th--11100111-1001011010.0编码后可以看到英文字符占1个字节,汉字占3个字节,共需要11个字节,如果直接存储Unicode码,需要14个字节。UTF-8编码为英文节省了很多空间,但为中文增加了空间。Littleendian和Bigendian上面提到Unicode用两个字节来表示字符。如果第一个字节在前就是“大端”(Bigendian),第二个字节在前就是“小端”。》(Littleendian)字符'世'的Unicode编码为4E16,一个字节为4E,一个字节为16。存储时,如果4E在前,则为大端存储,16在后前面,是小端存储。那么计算机怎么知道一个文件使用的是哪种编码方式呢?Unicode规范定义了在每个文件的前面加一个代表编码顺序的字符,这个字符的名字叫“零”widthno-breakspace”(零宽度不间断空间),用FEFF表示。正好是两个字节,FF比FE大1。如果一个文本文件的前两个字节是FEFF,则表示该文件采用大头法;如果前两个字节是FFFE,则表示该文件采用小头法。总结UTF-8编码是一种基于Unicode字符集的编码实现。现在几乎所有的编程语言和操作系统都支持Unicode编码,使用Unicode编码后,就再也不会出现那个尴尬的情况了t一个汉字等于上述两个英文字符。GBK、BIG5等都属于区域码,只能在固定范围内使用。比如GBK只适合简体中文使用。虽然GBK比UTF-8更节省空间,但是现在整个世界都变成了地球村,所以还是推荐大家使用UTF-8编码。ANSI:在Windows下,如果我们用记事本打开文档,经常会看到ANSI编码方式,这是Windows默认的编码方式。英文文档使用ASCII编码,简体中文文档使用GB2312编码(只针对Windows简体中文版,繁体中文版使用Big5编码)。
