第九章《字符串》第5节:字符编码常识

时间:2022-12-31 16:57:49

​专业上,把有公认意义的符号称之为“字符”,而一组字符形成的集合被称为“字符集”。字符集当中的每一个字符都有唯一的序号,这个序号是一个整数,用来和其他字符进行区别。

内存中的一个字节有8个位,每个位上的状态可以是0或1,这样,8个位就组合出256种状态,这256种状态就可以表示256个数字,而每一个数字又可以代表一个字符。因此,用一个字节就能表示出256个字符。美国国家标准协会把常用的字符进行了整理,形成了一个字符集。在这个字符集当中包含了大小写的英文字母、阿拉伯数字0到9,还有一些比较常用的符号,比如*号、#号等等。同时,美国国家标准协会还规定出了每个字符在这个集合当中的序号,例如,大写字母A在这个字符集合中序号是65。美国国家标准协会把这套字符集称之为“美国信息互换标准代码”,其英文全称为:American Standard Code for Information Interchange,按照首字母组合的缩写,人们简称这套代码为ASC码。​

ASC码是中的字符序号从0开始一直到了127,总共128个字符。127这个数字用二进制的方式来表示就是1111111,也就是连续的7个1。我们知道:一个字节是8个位,这连续的7个1放在一个字节的内存当中并没有占满一个字节,最前面还有一个空位,这个空位上的值是0。既然ASC码当中,编号最大的字符编码值最高位是0,那么其他的ASC码字符编码值最高位肯定也是0,因此,ASC码字符很明显的一个特征就是编码值的最高位都是0。​

ASC码字符当中,前32个字符属于控制字符。所谓控制字符是用来控制计算机或者是计算机的其他外围设备去做一个动作,比如编号为7的字符就表示响铃。当终端遇到这个字符的时候,就发出“嘟”的一声。从第33个字符开始一直到第127个字符都是可以打印出来的字符。这些字符包括字母、数字、加减号等等。而最后一个字符,代表着键盘上的退格键,这个字符同样也没法打印或者显示到任何终端上。​

用一个字节总共可以对256个字符进行编码,而ASC码字符只有128个,于是很多国家都用数字128到255对自己语言当中的字母或符号进行了编码,形成了新的字符集,这些字符集被称为扩展ASC码。扩展ASC并不是统一的编码,所以没有形成国际统一标准。但是,随着计算机在全世界的普及,并且各个国家之间交互的频繁程度越来越高,这些扩展出来的字符集也被广泛的使用,于是国际上把各种扩展ASC码表又进行了整理和重新命名,形成了ISO-8859-1到ISO-8859-15共15种版本的扩展形式。ISO-8859系列的扩展字符集当中每个字符的编码用二进制表示的话,每个字符编码最高位都是1,并且仍然只占用1个字节。​

欧美国家语言每个字符编码的最大是255,这是因为他们的语言体系中字符比较少,但中国人使用的汉字数量非常多,仅用0到255这些数字进行编码显然不够。为了解决这个问题,编码者规定每个汉字的编码必须占用两个字节的空间,这样的话就有足够多的数字对汉字进行编码。但使用这种思路在编码过程中又会产生新的问题。例如前文讲过:大写字母A的编码如果用二进制表示的话是01000001,那么当计算机读到内存中有两个连续的01000001,是该把这两个字节的数据解读为两个字母A呢,还是该把它解读成某个汉字呢?为了解决这个问题,编码者又规定:两个字节的数据在表示汉字的时候,每个字节的数据的最高位都必须是1,这样就跟ASC码能够区分开,因为标准的ASC码最高位都是0。​

按照这个规定,计算机如果在内存中读到某个字节的数据最高位是0,那么就认为这是一个标准的ASC码字符。并且还可以进一步确定,这个字节是可以独立表示字符的,不需要跟其他字节进行组合。相反,如果读到某个字节发现它的最高位是1,就说明这个字节是用来表示汉字的,并且必须要跟它相邻的一个字符合起来才能表示一个汉字。我们国家把这套编码方案起名为GB2312,其中“GB”就是国标的意思,国标是指“国家标准”而不是“国际标准”。早期这套编码方案只适用于中国*地区,后来新加坡等一些使用汉语的国家也采用了这套方案。​

从概念上严格来说,GB2312是一个字符集,这个字符集是一个针对简体汉字设计的字符集,它总共收录了六千七百多个汉字和一些其他国家的文字符号。另外,在GB2312这个字符集当中,只有最原始的ASC码字符是占一个字节,其他字符都是占两个字节。很多读者会问:之前讲过ISO-8859系列的扩展字符集当中那些新添加进来的字符不是也只占一个字节吗?在ISO-8859系列字符集当中那些字符确实只占一个字节。但是针对GB2312字符集,我们国家重新制定了编码规则,在新的规则当中,只有最原始的ASC码字符是占一个字节,其他字符都占两个字节。​

GB2312字符集解决了汉字的编码问题,但是这个字符集当中包含的汉字太少了,很多汉字都没有出现在字符集当中,针对这个问题,编码者又对GB2312字符集进行了一次扩展,形成了一个叫做GBK的字符集。在这个字符集中,又增加了20000多个汉字,其中包括了很多繁体字。GBK字符集仍然是用两个字节来表示原始的ASC码字符以外的其他字符。GBK这套字符集其实并不是国家标准总局颁布的,所以严格意义上来讲它并不是国家标准,GBK当中的那个字母K,其实是“扩展”的“扩”的拼音字母。因为GBK字符集的汉字数量更多,它的使用也非常广泛,所以虽然它不是国家标准,但是在行业内的地位与国家标准的字符集是相同的。并且更重要的是,GBK并没有改动GB2312的内容和编码,它对GB2312是完全兼容的。​

汉字编码的问题虽然解决了,但中国是一个多民族国家,很多少数民族都有自己的语言文字,他们也有使用计算机的需求,于是我国又创建了GB18030字符集,在这个字符集当中不仅仅包含了国内少数民族的文字符号,还包含了日语和韩语当中的汉字。​

全世界很多国家和地区都针对自身使用的语言文字指定了字符集,例如我国的*地区就针对繁体中文制定了Big5字符集。但是问题随之出现:各国各地区制定字符集并不统一,这样同一个字符在不同的字符集当中的编号各不相同,导致在网络上传输信息时总要进行编码转换,非常的麻烦。​

针对这个问题,国际标谁化组织制定了一个全球统一的字符集。在这个字符集当中包含了全球所有的符号,全球都统一使用这个字符集,就再也不需要在数据传输时进行编码转换了。国际标谁化组织给这个字符集取名为Universal Multiple-Octet Coded Character Set,简称UCS。在制定UCS字符集的时候人们提出了两种实现方案,分别是使用两个字节和四个字节去保存字符。如果使用两个字节去保存一个字符,那么两个字节共16位,可以组合出65536个字符。如果使用四个字节去保存字符,那么四个字节共32位,可以组合出42亿9千万多个字符。全球大多数使用的是两字节方案,这种方案简称为UCS-2,相应的,四字节方案的简称就是UCS-4。目前Java语言还没有与这个四字节方案对接,所以Java语言中总共有65536个字符,这些字符的编号是从0开始到65535。​

除国际标准化组织之外,还有一个叫做“统一码联盟”的组织,他们也制定了一个全球统一字符集,这个字符集就是Unicode字符集。后来,统一码联盟与国际标准化组织对UCS和Unicode进行了统一,使二者成为了统一的字符集。大部分使用Java的开发者习惯于把这种统一的字符集叫做Unicode。​

Unicode不仅仅是一个字符集,还提供了相应的编码实现方式。如果对Unicode字符集中所有字符都用2个字节来存储其编码,则这种编码方式称为UTF-16,其中数字16代表存储编码占用16位。这种编码方式与UCS-2用两个字节保存字符的思想完全吻合,因而简单易行。但这种编码方式对于存储ASC中的字符就会浪费存储空间,因为ASC码中的字符编号都小于128,也就是说,每个字符使用一个字节就完全可以存放ASC码中的字符编号。而UTF-16编码方式强制所有的字符都必须占两个字节,这就导致一份纯英文文档如果被保存成一个文件,所占用的空间会比理论上大出一倍,同样在网络上传输数据时,​

为了解决这个问题,人们又发明出了UTF-8的编码方式。UTF-8采用不固定长度的方式存储字符编码。例如大写的字母A,用UTF-16的编码方式来表示会占用两个字节。但A的编号是65,这个字符的编码只用一个字节的空间就能完成存储。UTF-8的编码规则规定:编号为0-127的字符在存储时都按一个字节存储,而编号大于127的字符在存储时占用多个字节。这样的话,所有ASC码字符在进行存储时会大量节约空间,因此这种编码方式最适合保存纯英文文档。需要注意:UTF-16和UTF-8都是在把文本文档保存在计算机硬盘上时所使用的编码方式,而在Java语言中把一个字符存储到内存空间中,这个字符无论编码是多少,都占用两个字节。​

本文字版教程还配有更详细的视频讲解,小伙伴们可以点击这里观看。