各种字符编码到底是个怎么回事

发布时间:2012-06-18作者: 邯郸翱翔

说起字符编码,相信做过一些开发的人都会接触过不止一种的字符编码,比如Ascii,GB2312,Big5,Unicode,UTF-8,各种各样的编码常常把我们搞得不知所措,一不小心就会出现乱码问题,今天
  说起字符编码,相信做过一些开发的人都会接触过不止一种的字符编码,比如Ascii,GB2312,Big5,Unicode,UTF-8,各种各样的编码常常把我们搞得不知所措,一不小心就会出现乱码问题,今天我们就来稀里糊涂的说说各种字符编码到底是个怎么回事。

      计算机这东西本质上是用来表示人类思维,帮助人类解决问题的一种机器,然而它是怎么表示人类思维的呢?我们知道计算机所能表示的只有2进制数字(靠高低电平实现),而我们人类的思维却是丰富多彩的,如何用简单的2进制数字来表示人类思维似乎成了一个不得不解决的复杂问题,人类思维这个话题是在太大了,我们很难对其做准确的定位,表示人类思维的问题就变得含糊不清,我们不妨把问题简单化,如何用计算机的2进制数据表示人类所应用的语言和字符呢?这样问题似乎变得简单了许多,我们知道二进制数据与十进制数据是可以互相转换的,也就说二进制数据与十进制数据本质上是没什么区别的,而十进制数据才是我们人类所熟悉的数据,在后面的内容中,我们常常会用十进制来代替二进制来进行说明(但是计算机内部可全部是由二进制表示的哦,我们用十进制只是为了说明起来方便,不要搞混了)。

注: 这里我们要插入一个字节的概念:计算机内部将8位二进制数据组成一个基本的存储单元叫做字节,8位二进制所能表示的数字范围是2的8次方,换算成十进制是256,也就是说一个字节最多可以表示256个不同信息。

      好了,接下来我们要进入编码的内部了,首先让我们举一个编码的简单例子,你知道“520”代表什么意思吗?呵呵,反应很快嘛,对的,“我爱你”,我们在网络上常常会用一些简单的数字来简化的表示一些词语,比如“520”代表“我爱你”,这其实就是一种简单的编码方式,"5"代表“我”、“2”代表“爱”、“0”代表“你”,这就是编码,没什么神奇的,以后无论多复杂的编码方式,其目的不过就像“520”代表“我爱你”一样,用特定的数字来代表代表特定的字符,建立数字与字符间的对应关系。看到这也许聪明的你已经有了用计算机表示人类字符的解决办法了,既然计算机只能表示数字,那我们只需要将我们平时所用的字符一一对应成数字,在计算机内储存一大堆数字,到时候把这堆数字读出来,然后按照我们所规定的对应关系重新对应成字符不就ok了吗?是的,你想的没错,我们现在的计算机正是这么干的。

       老美有一帮大牛们按照我们上面的这种想法最早的发明了一种编码叫做Ascii,这是一个单字节的字符编码方式(用一个字节来表示各种各样的字符,当然这时候只有英文字符,和少量的格式控制字符),Ascii规定0-127(我们发现其实它只用了一个字节8位中的7位)分别表示不同的数字,英文字母大写,英文字母小写,各种符号和一些计算机内部必须用到的格式控制字符(具体的Ascii编码表可以去百度一下,这里就不一一列出了),这种编码方式在早期的计算机当中使用了很久,大家似乎已经觉得我们似乎已经解决用计算机来表示人类字符的问题。然后不久问题就来了。

      随着计算机的发展,慢慢不止老美们再用计算机了,很多使用希腊字符和拉丁字符的欧洲国家也开始使用计算机,这些大佬们发现目前的计算机有着严重的问题,居然不能表示希腊字符,和拉丁字符,这是严重不能接受的,后来Ascii就针对这个问题对自身进行了扩充,将原来用7位表示字符扩充到了8位,形成了完整单字节字符,所能表示的字符范围也从128个扩展到了256个。这种编码方式又继续使用了很多年。

注: 以后的无论哪种编码方式都必须兼容Ascii,不然以前所有用Ascii编码的程序全部不能使用了。

     但是事情并没有结束,不久人们就发现,一个字节的编码远远满足不了人类的需求,我们除了使用英文字符,希腊字符,拉丁字符以外,我们还使用韩文,日文,简体中文,繁体中文。暂且不说别的,单单一个简体中文的字符量就远远超出了256,这时候我们迫切的希望有一种编码方式,能够解决我们的问题。后来各个国家就针对自己的语言做出了各自的编码方式,别的国家我们暂且不去管它,我们就来说说中国所用到的编码方式,最早我们提出了两种主要的编码方式:一种叫GB2312用来表示简体中文,一种叫Big5用来表示繁体中文。其中GB2312采用两个字节的编码方式,兼容Ascii,能够表示6千多个常用字(注意不是所有的汉字,仅仅是常用字),GB2312做了这样的规定,如果发现一个单个字节小于128,那么它表示一个英文字符(Ascii字符),如果发现一个单个字节大于(128),那么这个字节就和他后面的字节一起构成一个双字节字符(很多情况是汉字),这样我们就一定程度上的解决了汉字的编码方式,但显然GB2312有着严重的问题,缺字!给大家讲一个我自己的切身例子,我的名字原本叫梁霩阳,可在我出生的那个年代计算机还不能表示“霩”这个字,所以居然在我们的户口上写成了梁需阳,简直是坑爹啊,后来爸妈迫于无奈将我们的名字改成了梁阔洋。可以看出缺字是个很严重的问题,为了解决这个问题,GB2312规定了一些暂时不表示任何汉字的编码,如果你发现你所想表示的汉字在GB2312中没有,那么你可以利空这些空白编码自己造一个你所需要的汉字临时使用,不过这种方法显然是很麻烦的(不然估计我也不用改名了),后来到了win95/98的时代,人们将GB2312进行了扩展,起名字叫GBK,汉字扩展到了21003个,并且简体繁体融为一库,这时候很多不太常用的汉字也可以被表示了(包括我名字里边的那个“霩”字,⊙﹏⊙b汗)。

    然后问题并没有被完全解决,还有繁体中文呢,繁体中文也制定了一套编码叫做Big5(台湾省全部在用这个编码),Big5编码和GB2312编码编码方式是不同的,这就导致了一个很严重的问题,比如你在大陆用GB2312编码写了一封Email,这封Email发到台湾省,台湾省的同学们用Big5编码打开一看全是乱码,这种事情是很让人头疼的。类似的事情还有很多,比如日文韩文中也有很多的汉字(韩国历史甚至全部是用汉字写的),但日文韩文对汉字的编码和我们GB2312也是不一样的,也就是说韩国人全部用汉语写的东西发到大陆来,我们看到的还是乱码。

    后来呢,中日韩一起专门搞了一个编码,叫CJK编码,汉字在这个编码里变成了统一的编码,这样交流起来就不会有问题了,但这种问题不仅仅存在于中日韩,简体、繁体直接,这种问题在世界各国是广泛存在的。为了能统一解决这种问题,后来各大软件公司搞了一个联盟,叫做Unicode联盟,这个联盟的思想很简单,就会创造一种全世界统一的编码,能够把全人类使用的所有字符全部包含进去,以后人类全部使用这张编码,就再也不会有什么编码方式不一致所导致的乱码问题了,这种编码就是强大的Unicode编码。Unicode的存在似乎解决以往我们存在的所有编码问题,然后事物的发展都是一步一步进行的,Unicode也面临着挑战,这个挑战就是说服世界给地全部使用Unicode编码,然而这个任务到今天为止还没有做到(今天是2012/6/7)。打个比方,我们平常在Visual Studio中进行开发使用的是Unicode编码,而我们平时使用记事本写一个文件,以保存默认使用的是GB2312编码方式保存的。

    Unicode编码与以往的编码是不太一样的,以往的编码都是一个字符对应一个数字,比如Ascii中A对应数字65,但在Unicode中,一个字符真正对应计算机中的那个数字是有好几种不同存储方法的,也就是说一个字符有好几种不同的数字表示与之对应,这样做的好处是灵活,可以提供未来字符的扩展性(据说Unicode编码已经将未来宇宙统一所需要的编码都考虑进去了)。

    但目前,其实我们人类所使用的字符并不是很多,目前最常见的存储方法是双字节16位存储方式,两个字节最多可以表示6万多个字符,对于我们人类目前来说是足够用的了。

     由于存在着多种编码方式,当我们看到一堆十六进制、或者二进制字节,我们怎么知道它到底是哪种编码方式呢?以前的编码在内容中没有特殊的标记告诉你它用的是什么编码,看到字节的人必须提前知道它用的是什么编码方式才能对应的了解其中的内容,而Unicode专门规定了一个特殊的标记,叫做引导符也有叫引导续的,在开头用两个特殊的字节(FF FE),表示这个文件是用Unicode来进行编码的(你可以用任何二进制格式的工具打开一个Unicode编码的文件来检查一下,看看开头两个字节是不是FF FE),这样我们就不用提前知道(往往我们也不可能提前知道)这个文件到底是用什么编码方式来进行编码的,在开头看到这两个字节(FF FE)我们就知道这是一个用Unicode编码的文件,让事情变得更加简单了。这种引导符只有在Unicode中才有,其他编码格式中都没有,所以我们平时在处理文件的时候强烈建议使用Unicode来进行编码。

     上边我们说到了Unicode有很多种存法,我们常用的另外一种存法是UTF-8,这个存法和普通双字节十六位的Unicode存法是不同的,这个存法是有好处的:在普通的双字节十六位Unicode中,所有的字符都占两个字节,但对于英文来说其实一个字节就够了,剩下的那个字节就全部补0,这就导致了两个小问题,一个是空间浪费,另一个如果你并不知道这个文件是Unicode编码的,很多编码碰到十六进制00会认为字符串结束了,这就导致了程序可能不正常工作(当然这种情况应该已经很少发生了,因为Unicode前边是有引导符的 FF FE)。UTF格式就改善了以往的Unicode方法,UTF-8就是其中UTF一种,UTF-8是将普通的Unicode转换成中间没有0的方式来储存,这种存储方式让英文变得没有普通双字节Unicode所补的0,没有0意味着跟原来的ascii变得一模一样,也就是说原来的ascii一下变成了最新的UTF-8编码,这对于英文是十分方便的,但对于中文来中就不那么幸福了,每个中文字符变成了3个字节来表示,同样的字符数所需要的存储容量变得更大了,但目前硬件的存储容量现在已经很大了,我们不太在乎这一点点的容量变化,所以问题不大。UTF-8也有引导符,是三个字节的引导符(EF BB BF)。

      所以目前最广泛的Unicode储存方法有两种:1、内存中最常用的就是普通双字节十六位Unicode。2、存文件最常用的就是UTF-8的Unicode。

      在我们平时所做的开发中比如.net,所有的字符编码格式都是UTF-8,这也是我们希望看到的,我们在平时做开发时强烈建议使用UTF-8编码,这样可以避免很多编码上不必要的问题。至于如果我们碰到了不同的编码需要对其进行转换要怎么办,.net中处理方法是非常方便的,利用System.Text.Encoding这个类来对字符进行编码解码,去MSDN一下吧,简单易用。

关于我们
翱翔简介
青鸟简介
诚聘精英
在线咨询
热门课程
BCSP软件开发专业
云计算专业
大数据专业
Web前端专业
java开发专业
翱翔就业
就业案例
翱翔荣誉
微信 公众号 在线咨询 免费课程