计算机是如何存储字符的?
大学都学过计算机相关的基础知识,计算机只能计算二进制数据,因为二进制表示起来最方便。计算机电子元器件表示两个状态很简单,比如高压和低压,对应的就是1和0。如果设计出10种状态,那么计算机的设计会相当复杂。
计算机想存储我们现实世界的字符,也就是我们常用的汉子或者字母。最简单的方法就是把每个字符都对应一个数字,数字都能转为二进制,这样相当于计算机间接的存储了字符。实际上,计算机科学家们也的确是这么做的。由此,便诞生了各种字符集,各个国家的字符都有对应的数字。
都有哪些字符集
计算机发明之初,没有考虑那么多。作为现代计算机的发源地,当时也只考虑了美国的需求。所以只需要128个字符,称之为ASCII编码或者ASCII字符集(叫法不同而已,但是我觉得叫字符集更准确)。128个字符,如果用数字一一对应,一共只需7位二进制数字。计算机存储的最小单位是byte,即8位。ASCII字符集把最高位设置为0,用剩下的7位来表示字符。下图便展示了ASCII中,数字与字符的对应关系。
图中把ASCII字符集分为了两大部分,打印和非打印。打印部分好解释,就是会输出在显示设备上的,可以看看我们的键盘上,一般也都会有这些字符。非打印部分更多的是控制目的。比如NUL表示空字符, 表示换行, 表示回车等。
对于美国来说,ASCII是够用了,但是其他很多国家显然就不够用了。下面简单说说一些常见的。ISO 8859-1和Windows-1252。这两个都加入了西欧字符,两者基本一样,ISO 8859-1号称是用于西欧国家的标准字符集,但是Windows-1252更常用些。
中文的第一个标准字符集是GB2312,有大约7000个汉字和一些罕用词和繁体字。其使用两个字节表示汉字。GBK建立在GB2312的基础上,并向下兼容。共计包含了21000个汉字,其中包含了繁体字。GB18030进一步增强了GBK,同样可以向下兼容,共包含了76000个字符,其中有很多少数民族字符,以及中日韩统一字符。但是两个字节已经表示不了GB18030中的所有字符了,GB18030使用了长编码,有的字符是两个字节,有的是四个字节。两个字节的编码中,表示范围和GBK一样。除了以上表示中文的字符集外,还有个Big5,是针对繁体字的,广泛应用于湾湾省和香港那边。
前面说了这么多,是不是觉得很麻烦。不同的国家地区,还得用不用的字符集。前面讲到的所有字符集统称为非Unicode字符集。为了解决每个国家不同字符集间的不兼容现状,便有了Unicode字符集。它做了一件事,就是给世界上所有字符都分配了一个唯一的数字编号,有110多万,但大部分都在0x0000~0xFFFF之间,即65536个。
这些数字编号一般用16进制表示,但是要注意,只是分配了个数字编号,并不像上面的非Unicode字符集一样,这个数字也表示字符对应的二进制。至于Unicode字符集中,每个字符对应的二进制是多少,有几种不同的方案,主要有UTF-8、UTF-16、UTF-32。
UTF-32最简单,也符合我们的正常逻辑。数字编号的二进制形式,就是这个字符对应的二进制。缺点就是,每个字符都用四个字节表示,显然对于常用字符这是非常浪费的。UTF-16和GB18030一样,有个用两个字节有的用四个字节。UTF-8使用最广,其使用的是变长字节,每个字符使用的字节个数与Unicode中的数字编号有关。编号小的用的字节就少,编号大的用的字节就多,字节个数从1~4不等。
乱码怎么恢复
看到这里,为什么乱码相信你肯定知道了。无非就是使用了不同的字符集,导致解析错误。那么该怎么恢复乱码呢?如果你知道原编码方式最好,直接切换成对应的字符集即可。比如在一些可以切换编码方式的文本编辑器里、HTML的原信息设置、IDE的设置等。
但是如果不知道的话,也没什么太好的方式,只能一个个尝试了。我们可以写个简单的小程序,通过遍历常见字符集,来试着解析出乱码的原有格式。以Java为例:String newStr = new String(str.getBytes(charsets[i]),charsets[j])
。这句代码的意思就是:假设乱码str原来是charsets[j]编码的,被错误解析为charsets[i]编码的。在尝试前,切记要对原文件做备份,因为多次错误的解析和转换,可能很难再恢复成正常的字符了。