字符和编码¶
我们知道,现在的计算机是使用二进制来存储数据的。但是,对于人类使用的语言而言,即使是相对简单的英语,也有52个大小写字母、10个数字、各种标点符号和特殊符号等,远远超过了二进制的0和1两种状态;而计算机却能够正确地显示并处理这些字符。这究竟是怎么做到的呢?
一个非常容易想到的办法就是,给每一个字符分配唯一的一个编号,然后再使用二进制来表示该编号。通过建立字符和编号之间的唯一映射关系,我们就可以使用二进制来表示字符了。如果把许多个字符和编号之间的映射关系放在一起,就叫做字符集;至于如何建立字符和编号之间的映射关系,就叫做编码方案。
然而,一开始,不同厂家、不同地区等生产的计算机系统使用不同的编码方案,导致同一个编码在不同的系统上表现为不同的字符,对数据交换造成了严重的障碍。我们童年时候玩的新新魔塔就是一个非常典型的例子,其标题在中国的计算机上显示为“穝穝臸娥”,其中角色“暗黑大法师”被显示为“穞堵臸猭畍”,现在这个甚至成为了一个梗。
为了解决这个问题,也容易想到两种手段:要么利用一些方法来区分不同的编码方案,并在使用时指定编码方案;要么制定一个统一的编码方案,所有的计算机系统都使用这个编码方案。然而,前者的问题非常明显:如果这么做,那么所有的计算机都要存储所有的编码方案,这非常浪费空间;而且,如果用户不知道文件使用了哪种编码方案,那么就无法正确地显示文件内容。那么制定一个统一的编码方案反而成了一个不错的选择。这或许也是新时代的“书同文”吧。
最早的统一编码方案是美国人制定的ASCII编码。该编码使用7位二进制来表示128个字符,包含了英文字母、数字、标点符号和一些控制字符。例如,字母A的ASCII编码是65,字母a的ASCII编码是97,数字0的ASCII编码是48。可是世界上并非只有英语一种语言。为了兼容法语、德语等有变音符号的语言,后来又出现了ISO-8859(以Latin-1为代表)、扩展ASCII编码等,这些编码支持更多字符。
然而,当我们把目光投向亚洲时,我们发现了新的困难:以汉语为代表的亚洲语言有着数万个甚至数十万个字符,显然超过了上述编码的范围。为了促进国际交流,世界人民最终制定了一个统一的字符集:Unicode,或“统一码”。Unicode使用16位二进制来表示65536个字符,包含了世界上所有主要语言的字符以及一些符号和表情符号,同时该编码方案也完全兼容ASCII编码和扩展ASCII编码,例如0的Unicode编码仍然是48。后来也出现了扩展Unicode编码等,可以表示更多的字符。Unicode编码的出现极大地促进了国际交流和信息共享。为了和不同的计算机相适应,Unicode编码也有多种不同的表示方式,例如UTF-8、UTF-16、UTF-32等。其中,UTF-8是最常用的表示方式,它使用1到4个字节来表示一个字符,比较节省空间。Linux和mac OS系统默认使用UTF-8编码。
如果利用错误的编码方案来读取文件,就会出现乱码的问题。以下是常见的一些乱码及其原因,我们在看到这类乱码时,可以根据其原因来判断文件使用了哪种编码方案,从而选择正确的编码方案来读取文件。
乱码 | 原因 |
---|---|
锟斤拷 | GBK读UTF-8 |
大量非法字符和西欧字符 | UTF-8读GBK |
仅大量西欧字符,原文变长 | Latin1读UTF-8或GBK |
出现大量长得像yp的东西 | UTF-8读UTF-16 |
大量不认识的汉字 | GBK读Big-5 |
由于一些历史遗留问题,在Windows系统中,如果使用中文系统,则其编码方案通常是GBK(国标扩)。然而,该编码方案并不兼容Unicode编码,因此在处理Unicode编码的文件时,可能会出现乱码的问题。为了解决这个问题,Windows系统后来也提供了Unicode编码的支持,虽然系统本身依然使用GBK编码,但是在一些应用程序中会默认使用Unicode编码,例如记事本、Word等,且这些应用程序往往会自动识别文件的编码方案并进行转换。然而,对于一些从Linux等系统中移植来的软件往往是使用Unicode而非GB2312编码的,在Windows系统中运行这些软件时,可能会出现乱码的问题,因此,我们如希望使用一些移植软件,应当避免使用中文,或者在Windows系统中使用UTF-8编码。
在Windows 10以及以后的系统中,我们可以通过\texttt{设置>时间和语言>语言>管理语言设置>更改系统区域设置},来将系统的默认编码方案更改为UTF-8编码,从而避免乱码的问题。此类编码应在系统新安装时就启用,以保证不会出现乱码问题。