代码改变世界

URLENCODING,ASCII,UNICODE,UTF8,GBK

2011-11-18 15:17  AnyKoro  阅读(658)  评论(0编辑  收藏  举报

对于标题中所说的不同编码方式,我们下面逐一剖析。

1、URL ENCODING                                                                                                                                             

URLs只可以使用ASCII字符集在Internet上传输。

由于URLs经常会含有ASCII集之外的字符,此时URL就不得不将这些非ASCII的字符转换成有效的ASCII字符。

另外,URL encoding还会将不安全的ASCII字符使用以“%”开头后面紧跟两个十六进制数的形式,进行替换。

注意:

URLs是不能包含空格的。URL encoding一般会使用“+”号去替换空格。当然,也可以使用%20,这两种其实是一样的,只是一般前者是使用如下代码会得到

<form name="input" target="_blank" action="html_form_submit.asp" method="get">
<input type="text" value="Hello Günter" name="text" size="30">
<input type="submit" value="Submit">
</form>

当在input中填入一个空格,然后点击Submint时,会自动跳转到URL:“/html_form_submit.asp?text=+”,注意此处的空格变成了+

当使用JavaScript的escape()函数进行处理的时候,便会将空格处理成%20

重要解释:

其实URL encoding对于整个ascii都进行了编码,比如A为%41,B为%42,但是并一定会用到。因为URL本身就可以传输ascii,在前面也说了,有必要替换的无非也就是不安全的一些ascii数值,比如[、<之类的。那既然如此为什么还要对A等等进行编码呢?其实,这里应该抽象出去看。说到底,ASCII也就是一些二进制数(或说是十六进制数),他现有这些数值,然后让A,B去对应了这些值而已。这样的话,当对于例如UTF的情况,中文为三个字节,就可以认为是3个ASCII组成,比如一个中文字我,对应的ASCII码,如果拆成单个字节的ASCII码看的话,正好分别是 æ^',但是这是没有意义的,所以对于不同的编码会如何确认多少个字节为一组,因此我们传过去最好的传的是特定的编码(此处我的URL encoding为%E6%88%91,%后的其实就是对应的编码,可以认为组成了一组编号。)当后端接收到该字符后,再用特定的函数,可以对这些进行过URL encoding处理的字符串,再所反向处理。这也就是为什么这些反向处理函数需要选择当前传入的这些字符串是UTF8还是GBK,不同的语言决定了如何分段这些编码。这些处理程序,会把被URL encoding处理过的字符,根据指定的编码格式,然后解码出来。显示成我们人能读懂的格式。

所以这里看到的E6%88%91,你也可以认为是机器码,不同的机器码对应了不同的自然界符号。当然这些定义是我们人规定的。

1、ASCII                                                                                                                                                    

ASCII字符集被用于通过Internet在计算机间传递信息。ASCII是American Standard Code for Information Interchange的缩写。设计于60年代,并作为一种标准字符集广泛应用于计算机和其他硬件设备中。

ASCII是7位的字符集含有128字符,注意后来因为发展的需要,不够表示了,符号多了,于是将ASCII扩展成了8位的,正好一个字节,可以代表256个字符。扩展的主要是些全球其他国家比较通用的符号,比如£这个英镑符号,¥人民币符号,这些在最原始的ASCII码中是不包括的。当然这个改变后的ASCII不再叫ASCII,而是ISO 8859-1,又因为里面新增的字符时拉丁语,所以又成Latin-1.这就是著名的Latin编码方式。

这里主要说下原始的ASCII,其中主要包括了0-9的数字,a-z的字母(包括大写和小写)和一些特殊字符。

ASCII字符集广泛应用于现代计算机中,HTML,Internet都是基于ASCII的。

注意,这里有个很重要的理解,就是什么才是编码,是二进制或十六进制数才是编码,其对应的符号,只是图像。编码配合解码函数-》可读的符号。所以,要清楚编码是进制数。

这里着重讲下HTML Entity Code。在这个概念中有两个概念,一个事Entity Name,比如&nbsp;&copys;等等,还有个是Entity Number,比如&#160,&#169和前面的Entity Name是对应关系。为什么要引入HTML Entity Code呢?你想想,我们现在键盘能够表示键入的符号有多少个呢?你能在键盘上找到版权的符号吗?你是找不到的,但是明明ASCII中有,那么我们怎么才能输入呢。。。那么就是转码,就是用键盘可以输入的字符,组成一定的组合变成,键盘无法输入但是我们需要且ASCII中有的符号。OK。就这样。HTML Entity Code诞生了。那么Name和Number什么区别呢?就是两种表示方式而已。之所以没有用ASCII码直接显示,而是要再使用ASCII中转下的再显示的原因。主要还是我们的键盘。。表现力有限。如果可以把整个ASCII都能从键盘输入。那么也就没有必要这么中转了。

 

1、ANSI                                                                                                                                                     

 这个编码的出现,主要是因为需求的不断扩展,需要表示的符号,不断增多。但是其代表的是一种编码方式。即使用2个字节代表一个字符的延伸编码方式。这个方式没有没有严格的标准或规则去统揽全局。。。于是乎,编码的世界进入了一篇混沌。比方说,在简体中文系统中,ANSI编码代表GB2312编码,日文系统中ANSI编码代表JIS编码。不同的ANSI编码是不兼容的,想想也知道。。。肯定是由冲突的。相同的编码对应着不同的字符。这下就麻烦了。。。。不同的编码,如果使用两种不同的不同的编码方式,肯定显示不一样。。。,这就出现个问题,中文系统的东西。。日文系统看过去就是一堆乱码。。我如果想再日文系统中能显示中文,该怎么做呢?除非同时安装有日文语言包和中文语言包,否则很遗憾。。。没有办法。。。于是乎,为了解决这个问题,我需要在日文系统中能显示中文,那么我就需要一个统一编码方式,里面不仅含有中文的编码,还有日文的编码。。。所以,扩大编码的格式是必须的了。同时还有个更麻烦的问题,在同一套系统中如果处理多套的编码格式。。。OMG,你的处理程序估计就很混乱了。因此出现了一统江湖的Unicode。

当然ANSI并不是一无是处,对于强地域的应用,使用ANSI类编码还是很节约空间的。打个比方在中,做中国的应用使用GBK就行。除非对方没有安装中文语言包,否则是可以显示的。但是他无乱是传输用到的带宽还是Database用的空间,都比UTF要解决三分之一左右。

 

1、Unicode                                                                                                                                                     

 Unicode的中文名字很霸气——统一码、万国码、单一码。它为每种语言的每个字符设定了统一并且唯一的二进制码,以满足跨语言、跨平台进行文本转换、处理的要求。Unicode的编码形式是3个字节的,0-0x10FFFF。这里有个插曲,在制定该统一码的时候,还有个机构也在研究,就是ISO。制定出Unicode的是,统一码联盟。可喜的是,后来两者统一了。这里我们了解下,在ISO制定过程中出现的产物,USC-2,USC-4分别对应2个字节的编码和4个字节的编码。具体的内容这里就不详细说明了。作为统一的方式,就是ISO不会再扩展超过3个字节以上的字符编码编码方式了。目前实际应用的Unicode版本使用的16位的版本,对应于USC-2

但Unicode(和USC都)不适合传输,它是中定长的表示方法,很耗费资源。因为他没有明确的规定如何传输和存储。因为对于有些情况,比如低位的ASCII对应的字符,明明只要一个字节就可以保存。如果用3个字节也太浪费了。尤其当大量存在时,这个对网络带宽始终浪费。那么我们就需要有标记,标记哪里是尾部,哪里是首部。

于是UTF编码诞生了。UTF的全程式USC Transfer Format,如果想称为Unicode Transfer Format也问题不大。对于像对应的8,16,32。其实就是固定的编码大小。比如UTF-8是以1个字节作为最小的单位,UTF-16就是2个字节是最小的表示单位,UTF-32是以最小的表示单位为4个字节为最小单位的,这个也就是USC-4(基本不用了),这里也能看出是ISO提出的。既然统一了,那么通过增加Endian的方式来标记读取的方向,哪边是头哪边是尾。

这个有个概念叫BOM头。BOM头是用来在编码中规定方向的一种特殊编码,比如0XFFFF,0XFFFE分别对应BE(Big Endian)和LE(little Endian)(大尾和小尾)。

但是这个只是决定了读取方向的问题,还有个问题时何处是结束。这个就要使用到UTF中模板的概念了。

    其中UTF-16和Unicode编码大致一样, UTF-8就是以8位为单元对Unicode进行编码。从Unicode到UTF-8的编码方式如下:
     Unicode编码(16进制)      UTF-8 字节流(二进制) 
     000000 -00 007F         0xxxxxxx 
     000080 - 0007FF         110xxxxx 10xxxxxx 
     000800 - 00FFFF         1110xxxx 10xxxxxx 10xxxxxx 
             010000 -10FFFF        11110xxx 10xxxxxx 10xxxxxx  10xxxxxx

  例如“汉”字的Unicode编码是6C49。6C49在000800-00FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

他通过固定UTF-8中二进制字节流的基本形式,来进行处理。从上面的模板就可以看出,以0开头的肯定是1个字节的,以E打头的一定是3个字节的,其他的都是两个字节的。完美的完成了大小判断,配合方向,就知道每段是代表几个字节了。同时如果丢了个字节,从下个段开始又进行判断,该段式几个自己的。具有了非常好的容错。

扩展:

对于上面的模板知识,我们做进一步的研究。

上述机制,使得UTF8具有容错的能力,并且是一个动态大小的字节流,但是这样的机制会对本身UTF8容量造成影响,毕竟其中固定了一些位数。当然对于容量来说,只会对于高位的Unicode才会存在比Ansi更占空间的情况。这个从模板中可以看出来,在000000-0007FF的范围内,都是UTF-8的占用字节数是小于等于Unicode的,只有当高于这个范围时,才会出现UTF-8比Unicode费空间的情况,这也就是为什么UTF8对于英语网站来说会比用Unicode或Ansi更小的原因。

下面给出的列表,表示在一个文本中存入"1234567890"的内容,针对不同的编码,其大小也不同,这里主要比较UTF-8,Unicode,Ansi,GBK这4中形式

1、UTF-8   13BYTES Disk-4.096BTYPES

2、Unicode 22BYTES Disk -4.096BYTES

3、Ansi 10BTYES Disk-4.096 BYTES

 

4、GBK 13BYPTE Disk-40396BYTES

在来一组内容是“好人一生平安”的中文内容,这里中文的肯定是高位的情况

 

1、UTF-8   21BYTES Disk-4.096BTYPES

 

2、Unicode 14BYTES Disk -4.096BYTES

 

3、Ansi 12BTYES Disk-4.096 BYTES

 

 

4、GBK  12BTYES Disk-4.096 BYTES

这里要注意的是GBK其实是一种ANSI编码,当选择ANSI时候,他会自动选择最匹配的编码,比如输入中文的时候,选择ANSI他就会自动选择GB2312作为编码格式。

根据上面的情况,我们很容易发现,当存英文或数字的时候,UTF-8和GBK是一样的,这是因为他们都启用了,ASCII码的节约空间机制。而ANSI会比GBK等小的原因是,他有可能针对ASCII情况,进行了7位处理,比如像UTF-7的情况。对于中文的情况,因为他处于高位,所以可以发现其使用的空间情况比Unicode还多,这个就是有好有坏了。总之对于UTF-8来说对于英语国家很有利,对于中文国家。。上面的数据也说明了很不利。除非我们使用GBK。