程序员必须知道的计算机知识-字符编码ASCII,Unicode 和 UTF-8
ASCI码
众所周知,计算机内部的所有信息最终都是二进制值。每个二进制位(bit)有0和1两种状态,所以8个二进制位可以组合256种状态,称为字节(byte)。也就是说,一个字节可以用来表示256种不同的状态,每个状态对应一个符号,即256个符号,从0万到11111111。
20世纪60年代,美国制定了一套字符编码,统一规定了英语字符与二进制位的关系。这被称为ASCII码,至今一直在使用。
ASCII码规定了128个字符的编码,如空格SPACE为32(二进制001万),大写字母A为65(二进制01万)。这128个符号(包括32个无法打印的控制符号)只占一个字节的后7个,前一个统一规定为0。
二、非ASCII编码
用128个符号编码英语就够了,但用来表示其他语言,128个符号是不够的。例如,在法语中,如果字母上方有注音符号,则不能用ASCII码表示。因此,一些欧洲国家决定将新符号编入字节中闲置的最高水平。例如,法语编码为130(二进制1000010)。这样,这些欧洲国家使用的编码系统最多可以表示256个符号。
然而,这里又出现了新的问题。不同的国家有不同的字母,所以即使它们使用256个符号,代表的字母也是不同的。例如,130代表法语编码,在希伯来语编码中,字母Gimel代表(),另一个符号将代表俄语编码。但无论如何,0-127所表示的符号在所有这些编码方法中都是相同的,不同的只是128-255。
至于亚洲国家的文字,使用的符号更多,汉字多达10万左右。一个字节只能表示256个符号,肯定是不够的,所以一个符号必须用多个字节表示。比如简体中文常用的编码方法是GB2312,用两个字节表示一个汉字,理论上最多可以表示256×256=65536个符号。
中文编码的问题需要专题讨论,这个笔记不涉及。这里只指出,虽然一个符号用多个字节表示,但GB汉字编码与Unicode和UTF-8无关。
三.Unicode
正如上一节所说,世界上有很多编码方法,同一个二进制数字可以解释为不同的符号。因此,如果你想打开一个文本文件,你必须知道它的编码方法,否则如果你以错误的编码方式解释它,就会出现代码混乱。为什么电子邮件经常出现代码混乱?这是因为发件人和收件人使用不同的代码方法。
可以想象,如果有一个代码包含了世界上所有的符号。每个符号都给出了一个独特的代码,那么随机代码问题就会消失。这就是Unicode,就像它的名字一样,它是所有符号的代码。
当然,Unicode是一个很大的集合,目前的规模可以容纳100多万个符号。例如,每个符号的编码都不同U 阿拉伯字母Ain表示0639,U 0041表示英语大写字母A,U 4E25表示汉字严格。具体符号对应表可查询unicode.org,或专门的汉字对应表。
四、Unicode问题
需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,但没有规定如何存储二进制代码。
例如,汉字严格的Unicode是16进制数4E25,转换为15个二进制数(1001100100101),也就是说,这个符号至少需要两个字节。表示其他更大的符号可能需要三个字节或四个字节,甚至更多。
这里有两个严重的问题。第一个问题是如何区分Unicode和ASCII?计算机如何知道三个字节代表一个符号而不是三个符号?第二个问题是,我们已经知道英文字母只有一个字节就足够了。如果Unicode统一规定每个符号用三个或四个字节表示,那么在每个英文字母之前必须有两到三个字节为0,这对存储是一个巨大的浪费,文本文件的大小将是两到三倍,这是不可接受的。
结果是:1)Unicode存储方式多种多样,也就是说有很多不同的二进制格式,可以用来表示Unicode。2)Unicode直到互联网出现,才能长期推广。
五、UTF-8
互联网的普及强烈要求统一的编码方法。UTF-8是互联网上使用最广泛的Unicode实现方式。其他实现方式包括UTF-16(两个字节或四个字节表示字符)和UTF-32(四个字节表示字符),但基本上不在互联网上使用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。
UTF-8最大的特点之一是它是一种更长的编码方法。它可以用1~4个字节来表示符号,并根据不同的符号来改变字节长度。
UTF-8的编码规则很简单,只有两个:
1)对于单字节符号,字节的第一位是0,后七位是这个符号的Unicode码。所以对于英文字母,UTF-8编码与ASCII码相同。
2)n字节符号(n>1),第一个字节的前n位为1,第n位为1,第n位为1。
1位为0,后面字节的前两位为10。剩下的未提及的二进制位都是这个符号的Unicode码。
下表总结了编码规则,字母x表示可用编码的位置。
根据上表,解释UTF-8代码非常简单。如果一个字节的第一个是0,那么这个字节就是一个单独的字符;如果第一个是1,那么连续的1就意味着当前的字符占据了多少字节。
以汉字严为例,演示如何实现UTF-8编码。
严格的Unicode是4E25(1001100100101)。根据上表,可以发现4E25在第三行范围内(0000800-00000FFFF)。因此,严格的UTF-8编码需要三个字节,即格式为1110xxxxxxxxxxxxxx。然后,从严格的最后一个二进制位开始,从后到前填充格式中的x,多余的位补0。这样,严格的UTF-8编码为1100100110010010010101,转换为16进制为E4B8A5。
六、Unicode与UTF-8之间的转换
从上一节的例子可以看出,严格的Unicode码是4E25,UTF-代码是E4B8A5,两者不同。通过程序可以实现它们之间的转换。
Windows平台最简单的转换方法之一是使用内置记事本小程序notepad.exe。打开文件后,单击文件菜单中的另存作为命令,跳出对话框,底部有一个编码下拉条。
有四个选项:ANSI,Unicode,Unicodebigendian和UTF-8。
1)ANSI是默认的编码方式。英文文件是ASCII编码,简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版,Big5码会用)。
2)Unicode编码指的是notepad.exe使用的UCS-2编码方法,即直接将字符存储在两个字节中的Unicode码,该选项采用littlendian格式。
3)Unicodebigendian编码对应上一个选项。下一节我将解释littlendian和bigendian的含义。
4)UTF-8编码,也就是上一节提到的编码方法。
选择“编码方式”后,点击“保存”按钮,立即转换文件的编码方式。
七、Littlendian和Bigendian
上一节已经提到,UCS-2格式可以存储Unicode码(码点不超过0xFFFF)。以汉字严为例,Unicode码为4E25,需要存储两个字节,一个字节为4E,另一个字节为25。存储时,4E在前面,25在后面,这是Bigendian的方式;25在前面,4E在后面,这是Littlendian的方式。
这两个奇怪的名字来自英国作家斯威夫特的《格列佛游记》。在这本书中,内战在恶棍国家爆发。战争的原因是人们在争论吃鸡蛋时是否从大头开始(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事,前后爆发了六场战争。一个皇帝死了,另一个皇帝失去了王位。
第一个字节在前面,是“大头方式”(Bigendian),第二个字节在前面是“小头”(Littleendian)。
所以很自然,会有一个问题:计算机如何知道文件编码的方式?
Unicode规范定义,在每个文件的前面添加一个代表编码顺序的字符,称为“零宽度非换行空格”(zerowidthno-breakspace),用FEFF表示。这只是两个字节,FF比FE大1。
如果文本文件的前两个字节是FEFF,则表示文件是大头;如果前两个字节是FFFE,则表示文件是小头。
八、实例
下面,举个例子。
打开“记事本”程序notepad.exe,新文本文件的内容是一个严格的词,依次使用ANSI,Unicode,Unicodebigendian和UTF-保存8编码方法。
然后,用文本编辑软件Ultraedit中的“十六进制功能”观察文件的内部编码方法。
1)ANSI:文件的编码是两个字节D1CF,这是严格的GB2312编码,也暗示GB2312是大头存储的。
2)Unicode:四字节FFFE254E编码,其中FFFE表示为小头存储,真实编码为4E25。
3)Unicodebigendian:FEF4E25的编码为四个字节,其中FEF表示大头存储。
4)UTF-8:编码为六个字节EFBBFE4B8A5。前三个字节EFBBF表示,这是UTF-8编码,后三个E4B8A5是严格的具体编码,其存储顺序与编码顺序一致。
常见问题FAQ
- UU学院资源教程能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 付款了无法下载怎么办?
- 链接地址失效怎么办?