字符编码的简述

在计算机内部,所有的信息最终都表示为一个个的二进制位(bit)。每个二进制位有0和1两种状态,因此8个二进制位就可以组合出256种状态,这被称为一个字节(byte,即1个字节由8个二进制位组成)。也就是说,一个字节可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。

(由于采用0和1计数,会出现大量的01,不容易阅读,故采用16进制符号表示二进制位。一个16进制的字符能代表4个二进制位,故8个二进制位要使用两个16进制的字符,也即是说一个字节要用两个16进制的字符表示,如:11111111=0xFF。)

ASCII

计算机最先在美国实际应用。美国人制定了一套字符编码,对英语字符与二进制位之间的关系。把编号从0到32的分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。如遇上00x10, 终端就换行。我们把这些字节状态称为"控制码"。又把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号。这个方案叫做Ascii编码(American Standard Code for Information Interchange,美国信息互换标准代码)。

后来世界各地也开始使用计算机,很多国家用的不是英文,他们的字母里有许多是ASCII里没有的。为了可以在计算机保存他们的文字,他们决定采用 127号之后的空位来表示这些新的字母、符号,一直把序号编到了最后一个状态255。从128 到255这一页的字符集被称"扩展字符集"。

GB2312、GBK、GB18030

中国人使用计算机时,需要考虑到怎样保存汉字,怎样对汉字进行编码。一个字节不够用,那就使用两个字节,于是规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个常用简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。 这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展。

但是中国的汉字太多了,有许多人的名字都有生僻字。于是我们不得不继续把 GB2312 空闲的码位用上。但还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符 集里的内容。扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

后来又陆续扩展了少数民族的字和符号,GBK 扩成了 GB18030。 

Unicode、UCS

由于各个国家都搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,又怎么办?

国际组织决定着手解决这个问题。他们采用的方法很简单,废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码。

一种方案是unicode,叫做万国码、统一码,是统一码联盟的编码方案。

一种方案是UCS,叫做通用字符集,是ISO提供的编码方案。

双方意识到不需要2套通用的字符集,于是双方开始进行整合,到unicode2.0时,unicode的编码和ucs的编码都基本一致。所以很多人把unicode和ucs混成一谈,认为unicode就是ucs,ucs就是unicode,其实他们是各自发展的。

需要注意的是,Unicode只是一个符号集,它只规定了如何编码,并没有规定如何传输、保存这个编码。比如,汉字"严"的unicode是十六进制数4E25(0100 1110 0010 0101),也就是说这个符号的表示至少需要2个字节。其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题。1)如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?2)英文字母只用一个字节表示就够了,如果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,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

Unicode符号范围

UTF-8编码方式

               00-7F

0xxxxxxx

          00 80-07 FF

110xxxxx 10xxxxxx

     00 08 00-00 FF FF

1110xxxx 10xxxxxx 10xxxxxx

00 01 00 00-00 10 FF FF 

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

以汉字"严"为例。已知"严"的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(00 08 00-00 FF FF),需要三个字节,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。然后,从"严"的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,"严"的UTF-8编码是"11100100 10111000 10100101",转换成十六进制就是E4B8A5。

UCS-2

UCS有两种存储格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。UCS-2可以理解为UTF-16,可以指定le还是be。

另存文件时的Unicode就是指UCS-2的存储方式,即直接用两个字节存入字符的Unicode码。

 

Little endian和Big endian

还是以汉字"严"为例,Unicode码是4E25,使用ucs-2存储时,需要用两个字节存储,高位字节是4E,低位字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

Little-endian:将低序字节存储在起始地址(低位编址);Big-endian:将高序字节存储在起始地址(高位编址)。

每种存储方式都有存储单元的概念,如果存储单元超过一个字节,则要考虑LE还是BE的问题。如UTF-8则是单字节存储单元,则不用考虑是LE还是BE;而UTF-16、UCS-2是双字节存储单元,存储时需要考虑LE还是BE。目前好像只有UTF-16、UCS-2需要考虑LE和BE。其他的存储方式,如GB2312是默认BE。

Unicode规范中推荐的标记字节顺序的方法是BOM(Byte Order Mark)。每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用0xFEFF表示。这正好是两个字节。如果一个文本文件的头两个字节是FE FF,就表示该文件采用BE方式;如果头两个字节是FF FE,就表示该文件采用LE方式。

UTF-8文件的BOM是“EF BB BF”,但是UTF-8的字节顺序是不变的,因此这个文件头实际上不起作用。

总结

为了方便理解,可以把编码分成两个概念,一个是字符集编码方案,即每个字符用什么表示;一个是保存存储方案,即每个字符在文档中该怎么记录字符集。有些编码是把这两个概念合二为一的,如GB2312。有些是分开的,如unicode,编码方案是unicode,存储方案是utf-8或utf-16或其他。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值