解增言
2020-04-10 20:39
我们在上网时,偶尔会碰到打开的网页是乱码的情况。计算机上的文件名或文件内容,有时也显示为乱码。那么这些乱码是怎么造成的呢?
猫和狗在一起经常会打架,因为狗摇尾巴表示友好,而猫摇尾巴则表示遇到威胁;猫的咕噜声表示舒服,但狗要是发出低沉的咕噜声,那就是准备咬你了!这个其实就是信息编码不一样造成的。摇尾巴这个视觉信号和咕噜声这个听觉信号在猫和狗的语言中分别编码不同的信息,如果它们按照自己的编码去解读,就会造成误解,也就是产生了乱码。
那么,计算机的字符编码是怎么回事呢?
计算机只能理解二进制的语言,也就是只有0和1两种状态的语言。计算机最早是在美国发明的,美国人用的英语中,字母加上数字和标点符号,再加上控制符等其他常用符号一共不超过128个符号。1个二进制位只能表示21=2种状态,2个二进制位就能表示22=4种状态,所以要表示这些符号,我们需要至少7个二进制位(27=128)。在设计时,还预留了一位,一共用8个二进制位表示一个字符,其中最高位是0。为了方便,就用字节(Byte)表示这连续的8个二进制位(bit)。这也就是我们经常听说的ASCII码,基本的ASCII码表包括128个用7位二进制数表示的符号:
0 | x | x | x | x | x | x | x |
计算机引入到欧洲国家后,为表示一些英语中没有的特殊符号,如Ä以及希腊字母αβ等,就把最高位是1的编码也都用上了,这些就是扩展的ASCII码:
1 | x | x | x | x | x | x | x |
但其他国家的语言包括的符号要比这个多得多,如我们汉语中常用的汉字就有几千个,一个字节编码显然远远不够。为了编码更多的符号,人们就用两个字节编码一个字符,两个字节一共16位,理论上可以编码216=65536种符号。
|
|
但不同的国家和地区有不同的语言,于是就出现了很多编码方法,如我们国家大陆地区就有国标码(GB2312、GBK、GB18030等),港澳台地区有大五码(BIG5),另外还有包括中文、日文、韩文等语言符号的CJK(Chinese,Japanese和Korean的缩写)编码等,阿拉伯语国家也有他们自己的编码方法。由于不同的编码方式之间是相互独立的,所以如果一台计算机上没有安装相应的编码字符集,打开使用该字符集的网页时,就会显示乱码。
为了解决编码混乱的问题,人们提出了Unicode编码,将不同语言的中的各种符号用两个字节统一编码,原来ASCII码的部分,高位字节位全部为0。这样全世界人们都用同样的编码就可以了。
|
|
但是Unicode码编码任何字符都要2个字节,原来ASCII码中的字符也要2个字节,这对于信息的存储和传输造成了很大的浪费,尤其是网页在传输的时候,需要占用更多的带宽。于是人们又提出了Unicode码的传输格式UTF(Unicode Transformation Format)编码,UTF编码方案有多个版本,其中最常用的是UTF-8。
UTF-8是一种可变长度的编码方案,不同的字符分别由1-4个字节编码,常用的ASCII字符集部分由一个字节编码,最高位是0;其他字符包括扩展的ASCII字符集由2-4个字节编码,最高位字节有2-4个1后面跟1个0,几个1就表示由几个字节编码,其余字节都是以10开头。
Unicode编码(十六进制) | UTF-8 编码(二进制) |
---|---|
000000-00007F | 0xxxxxxx |
000080-0007FF | 110xxxxx 10xxxxxx |
000800-00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
010000-10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
在UTF-8字符集中,最常用的字符(英文字符、数字等)用一个字节编码,不常用的字符用多个字节编码,这样可以提高信息传输效率。绝大多数汉字都是由3个字节编码的,有些生僻字可能由4个字节编码,我们可以用cut或wc命令来测试一下。
$ ls
chinese_encoding
$ enca chinese_encoding
Universal transformation format 8 bits; UTF-8
$ cat chinese_encoding
中国
$ cut -b1 chinese_encoding
▒
$ cut -b1-2 chinese_encoding
▒
$ cut -b1-3 chinese_encoding
中
$ cut -c1 chinese_encoding
中
上面的例子中enca命令的作用是查看文件的编码方式。文件chinese_encoding文件中有“中国”两个汉字,使用cut -b1或cut -b1-2取出前面一个或两个字节时的内容都是乱码,而用cut -b1-3取出前面三个字节的内容或用cut -c1取出前面一个字符的内容时,则显示为正常的“中”字。这说明UTF-8编码中的汉字“中”字是由3个字节编码的。
Linux下可以方便地转换字符编码,例如我们把上面的文件转换为GB2312编码:
$ iconv -f UTF-8 -t GB2312 chinese_encoding >chinese_encoding_gb2312
$ ls
chinese_encoding chinese_encoding_gb2312
$ enca chinese_encoding_gb2312
Simplified Chinese National Standard; GB2312
iconv命令可以将常见的字符编码转换为另一种编码,-f和-t选项分别定义转换前和转换后的编码方式,默认结果输出到标准输出。关于字符编码查看和转换的命令enca和iconv的详细信息可以使用man命令查看其使用手册。如果系统中没有这两个命令的话,可以用sudo yum install(CentOS、Fedora)或sudo apt-get install(Ubuntu)安装。
制作网页时,网页文件的编码方式和头信息的meta标签中指定的编码方式一致,并且浏览用户电脑安装了该编码方式的字符集的话,网页显示就是正常的;如果网页文件编码和头信息中的不一致,或浏览用户电脑没安装该编码字符集,那么网页就会显示为乱码。由于UTF-8编码是全球通用的编码方式,绝大多数电脑都安装了该字符集,所以如果你制作网页的话,建议使用UTF-8编码,这样的话一般都会正常显示。如果使用GB系列编码,国内的电脑打开可能问题不大,但大部分老外的电脑上是没有安装GB系列字符集的,就会显示为乱码。