俄⽂unicode完整编码表_带你⾛进字符编码的世界
思考⼀下,为什么有字符编码这种东西?
当然是为了让计算机“听话”呗。我们知道,计算机的世界只有01这两个字符,⽽我们现实世界有成千上万的字符。如何⽤01的组合去和现实中的字符⼀⼀对应呢?这就是需要制定相应的编码规则来实现了。明⽩了这点,我们正式开始编码的讲解。
ASCII码
我们知道,在计算机内部,所有的信息最终都表⽰为⼀个⼆进制的字符串。每⼀个⼆进制位(bit)有0和1两种状态,因此⼋个⼆进制位就可以组合出256种状态(-128~127),这被称为⼀个字节(byte)。也就是说,⼀个字节⼀共可以⽤来表⽰256种不同的状态,每⼀个状态对应⼀个符号,就是256个符号,从0000000到11111111。
上个世纪60年代,美国制定了⼀套字符编码,对英语字符与⼆进制位之间的关系,做了统⼀规定。这被称为ASCII码,⼀直沿⽤⾄今。
ASCII码⼀共规定了128个字符的编码,⽐如空格“SPACE”是32(⼆进制00100000),⼤写的字母A是65(⼆进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占⽤了⼀个字节的后⾯7位,最
前⾯的1位统⼀规定为0。
ASCII码⽤了1个字节,1个字节可以表⽰256种状态,但ASCII码只⽤了128种,也就是⼀个字节的后七位,最前⾯的1位都是0。
⾮ASCII编码
英语⽤128个符号编码就够了,但是⽤来表⽰其他语⾔,128个符号是不够的。⽐如,在法语中,字母上⽅有注⾳符号,它就⽆法⽤ASCII 码表⽰。于是,⼀些欧洲国家就决定,利⽤字节中闲置的最⾼位编⼊新的符号。⽐如,法语中的é的编码为130(⼆进制10000010)。这样⼀来,这些欧洲国家使⽤的编码体系,可以表⽰最多256个符号。
但是,这⾥⼜出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使⽤256个符号的编码⽅式,代表的字母却不⼀样。⽐
如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中⼜会代表另⼀个符号。但是不管怎样,所有这些编码⽅式中,0—127表⽰的符号是⼀样的,不⼀样的只是128—255的这⼀段。
⾄于亚洲国家的⽂字,使⽤的符号就更多了,汉字就多达10万左右。⼀个字节只能表⽰256种符号,
肯定是不够的,就必须使⽤多个字节表达⼀个符号。⽐如,简体中⽂常见的编码⽅式是GB2312,使⽤两个字节表⽰⼀个汉字,所以理论上最多可以表⽰256x256=65536个符号。
中⽂编码的问题需要专⽂讨论,这篇笔记不涉及。这⾥只指出,虽然都是⽤多个字节表⽰⼀个符号,但是GB类的汉字编码与后⽂的Unicode和UTF-8是毫⽆关系的。
Unicode编码
正如上⼀节所说,世界上存在着多种编码⽅式,同⼀个⼆进制数字可以被解释成不同的符号。因此,要想打开⼀个⽂本⽂件,就必须知道它的编码⽅式,否则⽤错误的编码⽅式解读,就会出现乱码。为什么电⼦邮件常常出现乱码?就是因为发信⼈和收信⼈使⽤的编码⽅式不⼀样。
可以想象,如果有⼀种编码,将世界上所有的符号都纳⼊其中。每⼀个符号都给予⼀个独⼀⽆⼆的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表⽰的,这是⼀种所有符号的编码。
Unicode(统⼀码、万国码、单⼀码)是计算机科学领域⾥的⼀项业界标准,包括字符集、编码⽅案等。Unicode 是为了解决传统的字符编码⽅案的局限⽽产⽣的,它为每种语⾔中的每个字符设定了统⼀并且唯⼀的⼆进制编码,以满⾜跨语⾔、跨平台进⾏⽂本转换、处理的要求。
Unicode是国际组织制定的可以容纳世界上所有⽂字和符号的字符编码⽅案。⽬前的Unicode字符分为
17组编排,0x0000 ⾄
0x10FFFF,每组称为平⾯(Plane),⽽每平⾯拥有65536个码位,共1114112个。然⽽⽬前只⽤了少数平⾯。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码⽅案。
Unicode当然是⼀个很⼤的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不⼀样,⽐如,U+0639表⽰阿拉伯字母
Ain,U+0041表⽰英语的⼤写字母A,U+4E25表⽰汉字“严”。具体的符号对应表,可以查询,或者专门的汉字对应表。
Unicode的问题
需要注意的是,Unicode只是⼀个符号集,它只规定了符号的⼆进制代码,却没有规定这个⼆进制代码应该如何存储。⽐如,汉字“严”的unicode是⼗六进制数4E25,转换成⼆进制数⾜⾜有15位(100111000100101),也就是说这个符号的表⽰⾄少需要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码。
下表总结了编码规则,字母x表⽰可⽤编码的位。
Unicode符号范围 | UTF-8编码⽅式
(⼗六进制) | (⼆进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
下⾯,还是以汉字“严”为例,演⽰如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三⾏的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后⼀个⼆进制位开始,依次从后向前填⼊格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成⼗六进制就是E4B8A5。
那unicode和UTF-8有何区别?
Unicode 是「字符集」
UTF-8 是「编码规则」
字符集:为每⼀个「字符」分配⼀个唯⼀的 ID(学名为码位 / 码点 / Code Point)编码规则:将「码点」转换为字节序列的规则
BCD码
上⾯讲的是字符编码,是指⼀个字符对应的⼀个⼆进制数。⽽BCD码是计算机在对⼗进制数做运算或存储时采⽤的⼆进制格式。
Binary-Coded Decimal,简称BCD,称BCD码或⼆-⼗进制代码,亦称⼆进码⼗进数。是⼀种⼆进制的数字编码形式,⽤⼆进制编码的⼗进制代码。这种编码形式利⽤了四个位元来储存⼀个⼗进制的数码,使⼆进制和⼗进制之间的转换得以快捷的进⾏。
BCD码的优点是效率⾼:⽐如⼗进制要以⼆进制的形式在计算机中存储,⼗进制直接转换成与之对应的BCD码⽐⼗进制通过除法取余再转换的效率来的⾼。
Base64编码
定义:Base64是⽹络上最常见的⽤于传输8Bit字节码的编码⽅式之⼀,Base64就是⼀种基于64个可打印字符来表⽰⼆进制数据的⽅法。
为什么会有base64?
由于HTTP协议是⽂本协议,所以在HTTP协议下传输⼆进制数据需要将⼆进制数据转换为字符数据。然⽽直接转换是不⾏的。因为⽹络传输只能传输可打印字符。
问: 什么是“可打印字符”呢?
答: 在ASCII码中规定,0~31、128这33个字符属于控制字符,32~127这95个字符属于可打印字符,也就是说⽹络传输只能传输这95个字符,不在这个范围内的字符⽆法传输。
unicode汉字问: 那么该怎么才能传输其他字符呢?
答: 其中⼀种⽅式就是使⽤Base64。Base64⼀般⽤于在HTTP协议下传输⼆进制数据。
base64实现原理
Base64的索引与对应字符的关系如下表所⽰:
也就是说,如果将索引转换为对应的⼆进制数据的话需要⾄多6个Bit(2^6=64)。然⽽ASCII码需要8个Bit来表⽰,那么怎么使⽤6个Bit来表⽰8个Bit的数据呢?6个Bit当然不能存储8个Bit的数据,但是46个Bit可以存储38个Bit的数据啊
可以看到“Son”通过Base64编码转换成了“U29u”。这是刚刚好的情况,3个ASCII字符刚好转换成对应的4个Base64字符。但是,当需要转换的字符数不是3的倍数的情况下该怎么办呢?Base64规定,当需要转换的字符不是3的倍数时,⼀律采⽤补0的⽅式凑⾜3的倍数,具体如下表所⽰:
每6个Bit为⼀组,第⼀组转换后为字符“U”,第⼆组末尾补4个0转换后为字符“w”。剩下的使⽤“=”替代。
即字符“S”通过Base64编码后为“Uw==”。这就是Base64的编码过程。
好了,原理懂了,那么如果要进⾏base64编码,我们该怎么做呢?⾃⼰撸⼀个⽅法?⼀个库?都⾏,但是HTML规范中已经规定了base64转换的API,window对象上可以访问到base64编码和解码的⽅法,直接调⽤即可。
window.atob() // 对base64编码过的字符串进⾏解码
window.btoa() // 对ASCII编码的字符串进⾏base64编码(不⽀持汉字,汉字可通过URIencode预处理后再编码)
base64有哪些应⽤场景
前端将较⼩的icon编码为base64直接在⽂档中加载,减少http请求
电⼦邮件传输⼆进制⽂件时,通常⽤base64编码后再传
注意
base64编码后的数据量是要⽐编码前⼤的,所以base64不能⽤于减少数据量。
base64不能⽤于加密数据,即使使⽤私有的索引表也是不安全的。
关于转中⽂出错:btoa("中⽂") // The string to be encoded contains characters outside of the Latin1 range.意思就是超出⽀持范围,ASCII。
但是,如果你⾮要使⽤btoa来base64转码中⽂,也不是不⾏,就是略微蛋疼。如下:
MIME类型
每个MIME类型由两部分组成,前⾯是数据的⼤类别,例如声⾳audio、图象image等,后⾯定义具体的种类。
常见的MIME类型(通⽤型):
超⽂本标记语⾔⽂本 .html text/html
xml⽂档 .xml text/xml
XHTML⽂档 .xhtml application/xhtml+xml
普通⽂本 .txt text/plain
RTF⽂本 .rtf application/rtf
PDF⽂档 .pdf application/pdf
Microsoft Word⽂件 .word application/msword
PNG图像 .png image/png
GIF图形 .gif image/gif
JPEG图形 .jpeg,.jpg image/jpeg
au声⾳⽂件 .au audio/basic
MIDI⾳乐⽂件 mid,.midi audio/midi,audio/x-midi
RealAudio⾳乐⽂件 .ra, .ram audio/x-pn-realaudio
MPEG⽂件 .mpg,.mpeg video/mpeg
AVI⽂件 .avi video/x-msvideo
GZIP⽂件 .gz application/x-gzip
TAR⽂件 .tar application/x-tar
任意的⼆进制数据 application/octet-stream
URI编码解码
URL传输过程?
HTTP协议中参数组件的传输是key=value键值对的形式,如果要传输多个参数就需要⽤“&”符号对键值对进⾏分隔。例如?
name1=value1&name2=$value2,这样在服务器收到这种字符串的时候,会⽤“&”分隔出每⼀个参数,然后再⽤“=”来分隔出参数值。
针对name1=value1&name2=value2我们来说⼀下客户端到服务器端的概念上解析过程:
上述字符串在计算机中⽤ASCII码(16进制)表⽰为:6E616D6531 3D 76616C756531 26 6E616D6532 3D 76616C756532
服务器端在接收到该数据后就可以遍历该字节流,⾸先⼀个字节⼀个字节的读取,当读到3D这个字节的时候,服务器端就知道前⾯读到的字节串表⽰⼀个key,继续读取,如果遇到了26,表⽰从刚才读到的3D到26字节之间的字节串是上⼀个key的value,按照此⽅法就可以解析出客户端传过来的参数。
现在⼜这样⼀个问题:如果我的参数值中就包含=或者&这样的特殊⼦字符的时候,该怎么办。⽐如说name1=value1,其中value1的值是va&lu=e1,那么在传输过程中就会变成name1=va&lu=e1。⽤户传输的本意是只有⼀个键值对,但是服务器端会解析成两个键值对,这样就⾃然的产⽣了歧义。
如何解决上述问题带来的歧义呢?解决之法就是对URL进⾏编码
URL编码只是简单的在特殊字符的各个字节(16进制)前加上”%”即可。例如,我们对上述会产⽣歧义的字符(“va&lu=e1”)进⾏编码后的结果:name1=va%26lu%3D,这样服务器会把紧跟在”%”后的字节当成普通的字节,不会把它当成各个参数或键值对的分隔符。
另外⼀个问题是,为什么要⽤ASCII码传输,可不可以⽤别的编码?
因为⼀些历史的原因URL设计者使⽤US-ASCII字符集表⽰URL。(原因⽐如ASCII⽐较简单;所有的系统都⽀持ASCII)。当然可以⽤别的编码,你可以⾃⼰开发⼀套编码然后⾃⼰进⾏解析。就像⼤部分国家都有⾃⼰的语⾔⼀样。但是国家之间要怎么进⾏交流呢,⽤英语吧,英语的使⽤范围最⼴。
通常如果⼀样的东西需要编码,就说明这样的东西并不适合传输。⾄于原因有多种多样,size过⼤,包含隐私数据等等。对于URL来说,之所有要进⾏编码,是因为URL中有些字符会引起歧义。
例如,URL参数字符串中如果包含”&”或者”%”势必会造成服务器解析错误,所以需要对其进⾏编码。
⼜如,URL的编码格式采⽤的是ASCII码⽽不是Unicode,这也就是说你不能在URL中包含任何⾮ASCII字符,⽐如中⽂。否则如果客户端浏览器和服务器端浏览器⽀持的字符集不同的情况下,中⽂可能会造成问题。
URL编码的原则就是使⽤安全的字符(没有特殊⽤途或者特殊意义的可打印字符)去表⽰那些不安全的字符。
哪些字符需要编码
RFC3986⽂档规定,URL中只允许包含英⽂字母(a-zA-Z)、数字(0-9)、- _ . ~4个特殊字符以及所有的保留字符。RFC3986⽂档对URL 的编码解码问题做出了详细的建议,指出了哪些字符需要被编码才不会引起URL语义的转变,以及对为什么这些字符需要编码做出了相应的解释。
US-ASCII字符集中没有对应的可打印字符:URL中只允许使⽤可打印的字符。US-ASCII码中的10-7F字节全都表⽰控制字符,这些字符不能直接出现在URL中。同时对于80-FF字节,由于已经超出了AS
CII码定义字符的范围,因此也不能放在URL中。
保留字符:RUL可以划分为⼲了组件,协议、主机、路径等。有⼀些字符(: / ? # [ ] @)是⽤作分隔不同组件的。例如:冒号⽤于分隔协议和主机组件,斜杠⽤于分隔主机和路径,问号⽤于分隔路径和查询参数,等等。还有⼀些字符(! $ & * + , ; =)⽤于在每个组件中起到分隔作⽤,如等号⽤于表⽰查询参数中的键值对,&符号⽤于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进⾏编码。
RFC3986中指定了以下字符为保留字符: ! * ’ ( ) ; : @ & = + $ , / ? # [ ]
不安全字符:还有⼀些字符,当他们直接放在URL中的时候,可能会引起解析程序的歧义。这些字符被视为不安全的字符,原因有很多。
空格:URL在传输的过程,或者⽤户在排版的过程中,或者⽂本处理程序在处理URL的过程,都有可能引⼊⽆关紧要的空格,或者将那些有意义的空格给去掉。
引号 以及 <>:引号和尖括号通常⽤于在普通⽂本中起到分隔URL的作⽤。
警号#:通常⽤于表⽰书签或者锚点。
%:百分号本⾝⽤作对不安全的字符进⾏编码是使⽤的特殊字符,因此本⾝需要编码。
{ } | ^ [ ] ’ ~:某⼀些⽹关或者传输代理会篡改这些字符
需要注意的是,对于URL中的合法字符,编码和不编码是等价的,但是对于上边提到的这些字符,如果不经过编码,那么它们可能会造成URL语义的不同。因此对于URL⽽⾔,只有普通英⽂字符和数字,特殊字符$ - _ . + ! * ’ ( )还有保留字符,才能出现在未经编码的Url中,其他字符均需要编码之后才能出现在URL中。
但是由于历史原因,⽬前尚存在⼀些不标准的编码实现,例如对于”~”符号,虽然RFC3986⽂档规定,对于波浪号~不需要进⾏URL编码,但是还是有很多⽼的⽹关或者传输代理会进⾏编码。
如何对URL中的⾮法字符进⾏编码?
对于⾮ASCII字符,需要使⽤ASCII字符集的超集进⾏编码得到相应的字节,然后对每个字节执⾏百分号编码。对于Unicode字符,RFC⽂档建议使⽤utf-8对其进⾏编码得到相应的字节,然后对每个字节执⾏百分号编码。如”中⽂”使⽤UTF-8编码得到的字节是0xE4 0xB8
0xAD 0xE6 0x96 0x87,经过URL编码之后得到%E4%B8%AD%E6%96%87。
如果某个字符对应的ASCII字符集中的某个⾮保留字符,则此字节⽆需使⽤百分号表⽰。例如”Url编码”,使⽤UTF-8编码得到的字节是
0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,由于前三个字节对应着ASCII中的⾮保留字符”Url”,因此这三个字节可以⽤⾮保留字符”Url”表⽰。最终”Url编码”经过编码之后得到的是Url%E7%BC%96%E7%A0%81,当然,如果你
⽤%55%72%6C%E7%BC%96%E7%A0%81也是可以的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。