- 浏览: 673643 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
zhouyicang:
为嘛人气不够,这么好的文章,我找了几十篇博客,才找到这篇解惑了 ...
HTML 块级元素/内联元素 -
young7:
不错,解惑了
HTML 块级元素/内联元素 -
lvjin948:
获取浏览器语言的完美方案。http://blog.csdn.n ...
JavaScript获取浏览器语言类型 -
tarena_hhh:
我用了css优化工具,发现他的顺序有很大不一样?????
CSS属性书写顺序及命名规则 -
deng131:
谢谢你的提醒,是有个地方写错了
javascript事件绑定addEventListener,attachEvent
在日常的前端开发工作中,我们会经常的与HTML、javascript、css等语言打交道,和一门真正的语言一样,计算机语言也有它的字母表、语法、词法、编码方式等,在这里我简单的谈一下前端HTML与javascript日常工作中常碰到的编码问题。
在计算机中,我们储存的信息都是用二进制码表示的。我们认识的、屏幕上显示的英文、汉字等符号和储存用的二进制代码的互相转换,就是编码。
有两个基本概念需要说明,charset 和 character encoding:
charset ,字符集,也就是某个符号和某个数字映射关系的一个表,也就是它决定了107 是koubei 的 ‘a’,21475 是口碑的“口”,不同的表有不同的映射关系,如 ascii,gb2312,Unicode. 通过这个数字和字符的映射表,我们可以把一个二进制表示的数字转换成某个字符。
chracter encoding ,编码方式。例如,同是对于应“口”的 21475 这个数,我们是用 \u5k3e3 表示呢,还是用 %E5%8F%A3 来表示呢?这就是由 character encoding 来决定的。
对于 ‘koubei.com’ 这样的 字符串来说,是美国人的常用字符,他们就制定了一个 叫做ASCII 的字符集,全称是 american standard code of information interchange 美国标准信息交换码,用0–127这128个数字,(2的7次方,0×00-0×7f) 代表了123abc这样的常用的128个字符。一共是 7 bits,再加上第一个是符号位,要用来去补码反码表示负数什么的,一共8 bits 构成一个 byte。当年美国人就是小气了点,要是一开始就设计成一个 byte 是16 bits、32 bits,世界上会少很多问题,不过当时,估计他们觉得 8 bits 就够了,可以表示128个不同的字符呢!
介于计算机这玩意儿是美国人搞出来的,所以他们自己省事,把自家用的符号都编码好了,用的挺爽的。但当计算机开始国际化的时候,问题出来了,拿中国举例吧,汉字就好几万,怎么办?
现有的 8 bits 一个 byte 的系统是基础,不能破坏,不能去改到 16 bits之类的,否则改动太大了,只能走另一条路:用多个 ascii 的字符去表示一个其他字符,也就是 MBCS ( Multi-Byte Character System,多字节字符系统)。
有了这个 MBCS 的概念,我们可以表示更多个字符了,比如我们用 2 个 ascii 字符,就有 16 bits, 理论上有 2 的 16 次方 65536 个字符。但这些编码怎么分配到字符上呢?比如口碑的”口”的 Unicode 编码就是 21475,谁决定的呢?字符集,也就是刚刚介绍的charset。ascii就是最基础的一个字符集,在此之上,我们有类似于 gb2312, big5这样针对简体中文和繁体中文的MBCS的字符集等等。终于有个叫 Unicode Consortium 的机构,决定做一个囊括所有字符在内的字符集(UCS, Universal Character Set)和对应编码方式的标准,即 Unicode。从1991年开始,它发布了第一版 Unicode 国际标准,ISBN 0-321-18578-1 ,国际标准化组织 ISO 也参与了这个的定制,ISO/IEC 10646 : the Universal Character Set。总之,Unicode 是个基本覆盖了所有已经存在的地球上的符号的字符标准了,现在正在被越来越广泛的使用,ECMA 标准也规定,javascript语言的内部字符使用 Unicode 标准(这意味着,javascript的变量名、函数名等是允许中文的!)。
对于身在中国的开发者来说,可能碰到比较多的问题就是 gbk, gb2312, utf-8 之间转换之类的问题了。严格的说这个说法不是很准确,gbk,gb2312是字符集 (charset),而 utf-8 是一种编码方式 (character encoding) ,是 Unicode 标准中 UCS 字符集的一种编码方式,因为使用 Unicode 字符集的网页主要用UTF-8编码,所以大家常常就把它们并列了,其实是不准确的。
有了 Unicode 后,至少人类文明没有碰到外星人之前,这是一把钥匙了,都用它吧。而现在使用最广泛 Unicode 的编码方式就是 UTF-8 (8-bit UCS/Unicode Transformation Format) 了,它有几个特别好的地方:
1,编码 UCS 字符集,全世界通用
2,是一种变长编码方式(variable-length character encoding),兼容 ascii
第二点是个很大的优点,它使得以前使用纯 ascii 编码的系统兼容,而且不会增加额外的存储量(假设定长的编码方式,规定每个字符由2个 bytes 组成,那么这时候 ascii 字符占用的存储空间将增大一倍)。
要把 UTF-8 说清楚,引入一个表会更方便了:
U-00000000 – U-0000007F: 0xxxxxxx
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
要看懂这个表呢,我们看前两行就够了
U-00000000 – U-0000007F:
0xxxxxxx 第一行是这样的,意思是说,如果你发现一个utf-8编码的 byte 的二进制码是0xxxxxxx,是0开头的, 即十进制的0-127之间,那么他就是单独的这一 byte 代表一个字符,而且是拥有和 ascii 码完全一样的含义。其他所有的 utf8 编码的二进制值都是用1开头的1xxxxxxx,大于127的,而且都需要至少2 bytes才能代表一个符号。所以一个字节的第一位是一个开关,代表这个字符是不是一个 ascii 码。这个就是刚才谈到的兼容性,从英文定义上看,就是utf8编码的两个属性:
UCS characters U+0000 to U+007F (ASCII) are encoded simply as bytes 0×00 to 0×7F (ASCII compatibility). This means that files and strings which contain only 7-bit ASCII characters have the same encoding under both ASCII and UTF-8.
All UCS characters >U+007F are encoded as a sequence of several bytes, each of which has the most significant bit set. Therefore, no ASCII byte (0×00-0×7F) can appear as part of any other character.
然后我们看看第二行:
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
先看第一个字节:110xxxxx,它的含义是,我不是一个 ascii 码(因为第一位不为0),我是一个多 bytes 字符的第一个 byte (第二位为1),我参与表示的这个字符是由2个 bytes 组成的(第三位为0),从第四位开始,就是字符的信息储存的位置。
再看第二个字节:10xxxxxx,它的含义是:我不是一个 ascii 码(因为第一位不为0),我不是一个多 bytes 字符的第一个 byte (第二位为0),第三位开始是字符的信息储存的位置。
从这个例子中可以总结出来,utf-8编码方式中,在一长串连续的二进制 byte 码中,可能由2个至6个 bytes 来表示一个符号,那么相比较于用一个 byte 表示符号的 ascii 码,我们需要空间来储存两个额外信息: 一,这个符号开始位置,一个“starter”的位置,用生物学上的话来说,就是蛋白质翻译时候起始密码子AUG的位置了;二,这个符号使用的 bytes 数(其实如果每个符号都有 starter,这个长度是可以不提供的,但是提供长度信息增加了在部分 bytes 丢失时的容错能力)。解决方案是:用一个 byte 的第二位是否是1来代表这一 byte 是否是一个字符的起始 byte (因为一个 byte 里面的第一位刚才已经被使用了,0表示ascii码,1表示非ascii ),即,一个多字节符号的第一 个bytes一定是 11xxxxxx,一个192到255之间的二进制数。接下来,从第三位开始,提供长度信息,第三位是0表示这个符号是2字节的,第三位开始每多一个1,字符占用的 bytes 数加一。utf-8 最多定义到了 6 字节字符,需要比 110xxxxx 这样的表示2字节的starter多 4 个 1,所以这个starter就是 1111110x,如上表所示。
再看看英文定义的标准吧,表达的同样的意思:
The first byte of a multibyte sequence that represents a non-ASCII character is always in the range 0xC0 to 0xFD and it indicates how many bytes follow for this character. All further bytes in a multibyte sequence are in the range 0×80 to 0xBF. This allows easy resynchronization and makes the encoding stateless and robust against missing bytes.
真正的信息位(即,真正的charset字符集中的数字信息),是直接用二进制的方式,依顺序放在上面这个表的’x'上的。用我们中国程序员接触最多的汉字来说吧,它们的编码区间是在 U-00000800 – U-0000FFFF 之间的,从上面的表中可以查到,这个区间的 utf-8 编码是用三个字节来表示的(这就是 utf-8 编码的汉字会比每个字符占用2 bytes的 EUC-CN 编码的 gb2312 字符集的汉字使用更多储存空间的原因),还是用 口碑的”口”字举例吧,口字在 Unicode 中的编号是这样的:
口: 21475 == 0×53e3 == 二进制 101001111100011
在 javascript 中,run这段代码(使用 firebug 的 console,或者编辑一个HTML将下列代码插入一对 script 标签之间):
alert(‘\u53e3′); //get ‘口’
alert(escape(‘口’)); // get ‘%u53E3′
alert(String.fromCharCode(‘21475′)); // get ‘口’
alert(‘口’.charCodeAt(0)); // get ’21475‘
alert(encodeURI(‘口’)); //get ‘%E5%8F%A3′
可以看到,string直接量可以用\u+十六进制 Unicode 码的形式得到字符 ‘口’,而fromCharCode 方法接受 10 进制的 Unicode 码,得到字符 ‘口’。
其中第二个alert得到的是 ‘%u7545′ , 这是一种不标准的Unicode编码,是属于 URI 的 Percent encoding 一部分,但这种使用方法已经正式被 W3C 拒绝了,任何一个 RFC中都没有这个标准,ECMA-262 标准中规定了 escape 的这种行为,估计也是暂时的。
比较有意思的是第五次alert得到的 ‘%E5%8F%A3′ 这是什么呢?怎么得到的呢?
这就是在URI上用的比较多的 Percent encoding,百分号编码,RFC 3986 标准中规定的。
RFC 3986 规定,Percent encoding的非保留字如下:
Unreserved characters, per RFC 3986 (January 2005)
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 – _ . ~
也就是说,这些字出现在 URI 中的时候,不进行编码,因为他们和URI的格式没有关系,只是表示原义的字符
另外,保留字如下:
Reserved characters, per RFC 3986 (January 2005)
! * ‘ ( ) ; : @ & = + $ , / ? % # [ ]
这些字符,是有特殊意义的,如果在不代表那些特殊意义而代表原意的时候出现,必须经过编码,如下:
Reserved characters after percent-encoding
! * ‘ ( ) ; : @ & = + $ , / ? % # [ ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %25 %23 %5B %5D
而 % 号后面就是一个2位的十六进制数,这个数,就是 Unicode 的 UTF-8 编码的另一种表现形式。
让我们详细还原一下’口’ 字为什么是 ‘%E5%8F%A3′ 吧。
刚才我们谈到 ‘口’ 的 Unicode 编码 21475 的二进制形式是:
101001111100011
刚才我们又聊到,对于一个的汉字,它的UTF-8编码的形式是:
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
现在我们做个填空题,把 ‘口’ 二进制码切开填进去替换掉 x:
101001111100011 = ----0101 --001111 --100011
101001111100011 = 1110xxxx 10xxxxxx 10xxxxxx
第一个字节少一位,左边加个0补齐,得到:
11100101 10001111 10100011
让我们把这三个二进制数转换成16进制,并且加上百分号,运行如下javascript代码:
alert(
‘%’ + parseInt(‘11100101′, 2).toString(16) +
‘%’ + parseInt(‘10001111′, 2).toString(16) +
‘%’ + parseInt(‘10100011′, 2).toString(16)
) // get ‘%e5%8f%a3′
怎么样,得到 %e5%8f%a3 了吧。
另外javascript的内置函数 encodeURI、decodeURI、encodeURIComponent、decodeURIComponent 就是进行的 Percent Encode,只是在对待 : / ; ?等特殊字符的时候有区别。
另外,再介绍一下 HTML 中的 Numeric character reference, NCR编码
相信大家都知道,HTML中的特殊字符是需要编码的,比如 & 需要被编码为: & 还有 ® 这样的特殊字符。其实HTML也是可以利用 Unicode 编码来显示任何一个字符的,编辑一个如下的html文件:
<html>
<body>
口
口
口
</body>
</html>
结果就是三个“口”字。
还有一种常用的编码是 base64 编码,base64编码本来是为了在 email 这样的非纯 8-bit 的传输层传输二进制数据而设计出来的,这样就可以在 email 中传递二进制的附件。它用 a-z A-Z 0-9 +/= 这64个字符来表示原有的数据,并且将连续的三个字符编码为四个,长度增加33%。
这个编码方式在一些比较超前的 javascript 应用中比较常用,例如 这个超级玛丽游戏 ,它里面的音乐就是写 javascript 文件中的。例如 这个 利用 canvas 作图的例子,里面的头像也是写在 javascript 源代码中的。这就是 RFC 2397 规定的 data URIs 协议,Firefox 浏览器支持,IE8也开始部分支持了,利用 data URIs 和 base64 编码,我们可以不借助任何外来的音乐、图像等多媒体文件而创造出丰富的效果。
以上就是我想介绍的 javascript 和 html 中常用到的编码和原理,最后还想提到一句,很多的黑客行为都和编码有关,用编码后的代码来通过一些简单的过滤,如下js代码:
var a = ‘口碑’;
\u0061 = ‘koubei.com’;
alert(a); //get ‘koubei.com’
当然,黑客们会有更专业的方式来逃避过滤、注入代码(如 sql injection, XSS 攻击等)。
谢谢大家的阅读,我是 stauren, 雅虎口碑UED团队的前端开发工程师粽子,这是我第一次在Koubei的UED blog上发表文章,如果有错误的地方请大家指出。同时欢迎访问我的个人blog : http://stauren.net, 并且提供在线 Hex、NCR、Percent encode、Base64编码解码工
在计算机中,我们储存的信息都是用二进制码表示的。我们认识的、屏幕上显示的英文、汉字等符号和储存用的二进制代码的互相转换,就是编码。
有两个基本概念需要说明,charset 和 character encoding:
charset ,字符集,也就是某个符号和某个数字映射关系的一个表,也就是它决定了107 是koubei 的 ‘a’,21475 是口碑的“口”,不同的表有不同的映射关系,如 ascii,gb2312,Unicode. 通过这个数字和字符的映射表,我们可以把一个二进制表示的数字转换成某个字符。
chracter encoding ,编码方式。例如,同是对于应“口”的 21475 这个数,我们是用 \u5k3e3 表示呢,还是用 %E5%8F%A3 来表示呢?这就是由 character encoding 来决定的。
对于 ‘koubei.com’ 这样的 字符串来说,是美国人的常用字符,他们就制定了一个 叫做ASCII 的字符集,全称是 american standard code of information interchange 美国标准信息交换码,用0–127这128个数字,(2的7次方,0×00-0×7f) 代表了123abc这样的常用的128个字符。一共是 7 bits,再加上第一个是符号位,要用来去补码反码表示负数什么的,一共8 bits 构成一个 byte。当年美国人就是小气了点,要是一开始就设计成一个 byte 是16 bits、32 bits,世界上会少很多问题,不过当时,估计他们觉得 8 bits 就够了,可以表示128个不同的字符呢!
介于计算机这玩意儿是美国人搞出来的,所以他们自己省事,把自家用的符号都编码好了,用的挺爽的。但当计算机开始国际化的时候,问题出来了,拿中国举例吧,汉字就好几万,怎么办?
现有的 8 bits 一个 byte 的系统是基础,不能破坏,不能去改到 16 bits之类的,否则改动太大了,只能走另一条路:用多个 ascii 的字符去表示一个其他字符,也就是 MBCS ( Multi-Byte Character System,多字节字符系统)。
有了这个 MBCS 的概念,我们可以表示更多个字符了,比如我们用 2 个 ascii 字符,就有 16 bits, 理论上有 2 的 16 次方 65536 个字符。但这些编码怎么分配到字符上呢?比如口碑的”口”的 Unicode 编码就是 21475,谁决定的呢?字符集,也就是刚刚介绍的charset。ascii就是最基础的一个字符集,在此之上,我们有类似于 gb2312, big5这样针对简体中文和繁体中文的MBCS的字符集等等。终于有个叫 Unicode Consortium 的机构,决定做一个囊括所有字符在内的字符集(UCS, Universal Character Set)和对应编码方式的标准,即 Unicode。从1991年开始,它发布了第一版 Unicode 国际标准,ISBN 0-321-18578-1 ,国际标准化组织 ISO 也参与了这个的定制,ISO/IEC 10646 : the Universal Character Set。总之,Unicode 是个基本覆盖了所有已经存在的地球上的符号的字符标准了,现在正在被越来越广泛的使用,ECMA 标准也规定,javascript语言的内部字符使用 Unicode 标准(这意味着,javascript的变量名、函数名等是允许中文的!)。
对于身在中国的开发者来说,可能碰到比较多的问题就是 gbk, gb2312, utf-8 之间转换之类的问题了。严格的说这个说法不是很准确,gbk,gb2312是字符集 (charset),而 utf-8 是一种编码方式 (character encoding) ,是 Unicode 标准中 UCS 字符集的一种编码方式,因为使用 Unicode 字符集的网页主要用UTF-8编码,所以大家常常就把它们并列了,其实是不准确的。
有了 Unicode 后,至少人类文明没有碰到外星人之前,这是一把钥匙了,都用它吧。而现在使用最广泛 Unicode 的编码方式就是 UTF-8 (8-bit UCS/Unicode Transformation Format) 了,它有几个特别好的地方:
1,编码 UCS 字符集,全世界通用
2,是一种变长编码方式(variable-length character encoding),兼容 ascii
第二点是个很大的优点,它使得以前使用纯 ascii 编码的系统兼容,而且不会增加额外的存储量(假设定长的编码方式,规定每个字符由2个 bytes 组成,那么这时候 ascii 字符占用的存储空间将增大一倍)。
要把 UTF-8 说清楚,引入一个表会更方便了:
U-00000000 – U-0000007F: 0xxxxxxx
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
要看懂这个表呢,我们看前两行就够了
U-00000000 – U-0000007F:
0xxxxxxx 第一行是这样的,意思是说,如果你发现一个utf-8编码的 byte 的二进制码是0xxxxxxx,是0开头的, 即十进制的0-127之间,那么他就是单独的这一 byte 代表一个字符,而且是拥有和 ascii 码完全一样的含义。其他所有的 utf8 编码的二进制值都是用1开头的1xxxxxxx,大于127的,而且都需要至少2 bytes才能代表一个符号。所以一个字节的第一位是一个开关,代表这个字符是不是一个 ascii 码。这个就是刚才谈到的兼容性,从英文定义上看,就是utf8编码的两个属性:
UCS characters U+0000 to U+007F (ASCII) are encoded simply as bytes 0×00 to 0×7F (ASCII compatibility). This means that files and strings which contain only 7-bit ASCII characters have the same encoding under both ASCII and UTF-8.
All UCS characters >U+007F are encoded as a sequence of several bytes, each of which has the most significant bit set. Therefore, no ASCII byte (0×00-0×7F) can appear as part of any other character.
然后我们看看第二行:
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
先看第一个字节:110xxxxx,它的含义是,我不是一个 ascii 码(因为第一位不为0),我是一个多 bytes 字符的第一个 byte (第二位为1),我参与表示的这个字符是由2个 bytes 组成的(第三位为0),从第四位开始,就是字符的信息储存的位置。
再看第二个字节:10xxxxxx,它的含义是:我不是一个 ascii 码(因为第一位不为0),我不是一个多 bytes 字符的第一个 byte (第二位为0),第三位开始是字符的信息储存的位置。
从这个例子中可以总结出来,utf-8编码方式中,在一长串连续的二进制 byte 码中,可能由2个至6个 bytes 来表示一个符号,那么相比较于用一个 byte 表示符号的 ascii 码,我们需要空间来储存两个额外信息: 一,这个符号开始位置,一个“starter”的位置,用生物学上的话来说,就是蛋白质翻译时候起始密码子AUG的位置了;二,这个符号使用的 bytes 数(其实如果每个符号都有 starter,这个长度是可以不提供的,但是提供长度信息增加了在部分 bytes 丢失时的容错能力)。解决方案是:用一个 byte 的第二位是否是1来代表这一 byte 是否是一个字符的起始 byte (因为一个 byte 里面的第一位刚才已经被使用了,0表示ascii码,1表示非ascii ),即,一个多字节符号的第一 个bytes一定是 11xxxxxx,一个192到255之间的二进制数。接下来,从第三位开始,提供长度信息,第三位是0表示这个符号是2字节的,第三位开始每多一个1,字符占用的 bytes 数加一。utf-8 最多定义到了 6 字节字符,需要比 110xxxxx 这样的表示2字节的starter多 4 个 1,所以这个starter就是 1111110x,如上表所示。
再看看英文定义的标准吧,表达的同样的意思:
The first byte of a multibyte sequence that represents a non-ASCII character is always in the range 0xC0 to 0xFD and it indicates how many bytes follow for this character. All further bytes in a multibyte sequence are in the range 0×80 to 0xBF. This allows easy resynchronization and makes the encoding stateless and robust against missing bytes.
真正的信息位(即,真正的charset字符集中的数字信息),是直接用二进制的方式,依顺序放在上面这个表的’x'上的。用我们中国程序员接触最多的汉字来说吧,它们的编码区间是在 U-00000800 – U-0000FFFF 之间的,从上面的表中可以查到,这个区间的 utf-8 编码是用三个字节来表示的(这就是 utf-8 编码的汉字会比每个字符占用2 bytes的 EUC-CN 编码的 gb2312 字符集的汉字使用更多储存空间的原因),还是用 口碑的”口”字举例吧,口字在 Unicode 中的编号是这样的:
口: 21475 == 0×53e3 == 二进制 101001111100011
在 javascript 中,run这段代码(使用 firebug 的 console,或者编辑一个HTML将下列代码插入一对 script 标签之间):
alert(‘\u53e3′); //get ‘口’
alert(escape(‘口’)); // get ‘%u53E3′
alert(String.fromCharCode(‘21475′)); // get ‘口’
alert(‘口’.charCodeAt(0)); // get ’21475‘
alert(encodeURI(‘口’)); //get ‘%E5%8F%A3′
可以看到,string直接量可以用\u+十六进制 Unicode 码的形式得到字符 ‘口’,而fromCharCode 方法接受 10 进制的 Unicode 码,得到字符 ‘口’。
其中第二个alert得到的是 ‘%u7545′ , 这是一种不标准的Unicode编码,是属于 URI 的 Percent encoding 一部分,但这种使用方法已经正式被 W3C 拒绝了,任何一个 RFC中都没有这个标准,ECMA-262 标准中规定了 escape 的这种行为,估计也是暂时的。
比较有意思的是第五次alert得到的 ‘%E5%8F%A3′ 这是什么呢?怎么得到的呢?
这就是在URI上用的比较多的 Percent encoding,百分号编码,RFC 3986 标准中规定的。
RFC 3986 规定,Percent encoding的非保留字如下:
Unreserved characters, per RFC 3986 (January 2005)
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 – _ . ~
也就是说,这些字出现在 URI 中的时候,不进行编码,因为他们和URI的格式没有关系,只是表示原义的字符
另外,保留字如下:
Reserved characters, per RFC 3986 (January 2005)
! * ‘ ( ) ; : @ & = + $ , / ? % # [ ]
这些字符,是有特殊意义的,如果在不代表那些特殊意义而代表原意的时候出现,必须经过编码,如下:
Reserved characters after percent-encoding
! * ‘ ( ) ; : @ & = + $ , / ? % # [ ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %25 %23 %5B %5D
而 % 号后面就是一个2位的十六进制数,这个数,就是 Unicode 的 UTF-8 编码的另一种表现形式。
让我们详细还原一下’口’ 字为什么是 ‘%E5%8F%A3′ 吧。
刚才我们谈到 ‘口’ 的 Unicode 编码 21475 的二进制形式是:
101001111100011
刚才我们又聊到,对于一个的汉字,它的UTF-8编码的形式是:
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
现在我们做个填空题,把 ‘口’ 二进制码切开填进去替换掉 x:
101001111100011 = ----0101 --001111 --100011
101001111100011 = 1110xxxx 10xxxxxx 10xxxxxx
第一个字节少一位,左边加个0补齐,得到:
11100101 10001111 10100011
让我们把这三个二进制数转换成16进制,并且加上百分号,运行如下javascript代码:
alert(
‘%’ + parseInt(‘11100101′, 2).toString(16) +
‘%’ + parseInt(‘10001111′, 2).toString(16) +
‘%’ + parseInt(‘10100011′, 2).toString(16)
) // get ‘%e5%8f%a3′
怎么样,得到 %e5%8f%a3 了吧。
另外javascript的内置函数 encodeURI、decodeURI、encodeURIComponent、decodeURIComponent 就是进行的 Percent Encode,只是在对待 : / ; ?等特殊字符的时候有区别。
另外,再介绍一下 HTML 中的 Numeric character reference, NCR编码
相信大家都知道,HTML中的特殊字符是需要编码的,比如 & 需要被编码为: & 还有 ® 这样的特殊字符。其实HTML也是可以利用 Unicode 编码来显示任何一个字符的,编辑一个如下的html文件:
<html>
<body>
口
口
口
</body>
</html>
结果就是三个“口”字。
还有一种常用的编码是 base64 编码,base64编码本来是为了在 email 这样的非纯 8-bit 的传输层传输二进制数据而设计出来的,这样就可以在 email 中传递二进制的附件。它用 a-z A-Z 0-9 +/= 这64个字符来表示原有的数据,并且将连续的三个字符编码为四个,长度增加33%。
这个编码方式在一些比较超前的 javascript 应用中比较常用,例如 这个超级玛丽游戏 ,它里面的音乐就是写 javascript 文件中的。例如 这个 利用 canvas 作图的例子,里面的头像也是写在 javascript 源代码中的。这就是 RFC 2397 规定的 data URIs 协议,Firefox 浏览器支持,IE8也开始部分支持了,利用 data URIs 和 base64 编码,我们可以不借助任何外来的音乐、图像等多媒体文件而创造出丰富的效果。
以上就是我想介绍的 javascript 和 html 中常用到的编码和原理,最后还想提到一句,很多的黑客行为都和编码有关,用编码后的代码来通过一些简单的过滤,如下js代码:
var a = ‘口碑’;
\u0061 = ‘koubei.com’;
alert(a); //get ‘koubei.com’
当然,黑客们会有更专业的方式来逃避过滤、注入代码(如 sql injection, XSS 攻击等)。
谢谢大家的阅读,我是 stauren, 雅虎口碑UED团队的前端开发工程师粽子,这是我第一次在Koubei的UED blog上发表文章,如果有错误的地方请大家指出。同时欢迎访问我的个人blog : http://stauren.net, 并且提供在线 Hex、NCR、Percent encode、Base64编码解码工
发表评论
-
IE浏览器stylesheets加载资源限制问题
2015-03-08 20:30 1072@import url()做一下总结: 1:@import ... -
理解Javascript原型及继承
2012-08-15 22:13 1346js初次使用起来觉得很简单但是在使用一段时间后很不深入的理解原 ... -
JS判断IE浏览器支持版本
2012-02-01 19:00 2968/* * @description 判断是否是IE,返回具体 ... -
jsonp动态创建script方式IE9问题
2012-02-01 16:28 2384在IE9浏览器创建一个script元素,然后指定其src属性u ... -
IE9下使用jsonp方式调用问题
2012-01-31 19:03 22921. 如果JSONP返回的Content-Type不符合规范, ... -
JavaScript获取浏览器语言类型
2011-12-31 18:24 7807获取浏览器语言: IE: navigator.browser ... -
IE Security Comprehensive Protection
2011-12-19 20:14 1766IE浏览器安全方面的处理,本人英文不好建议大家直接看英文: ... -
javaScript 中比较数字字符串问题
2011-10-10 21:49 4674在实现前端页面排序功能过程中遇到的问题,由于自己的粗心导致了生 ... -
javascript设置label标签 for属性
2011-09-11 10:36 3607js创建label标签的for属性用来增加操作响应区域。 v ... -
javascript事件绑定addEventListener,attachEvent
2011-07-31 18:55 3523为了考虑浏览器的兼容性问题,都需要对浏览器进行类型检测。 f ... -
readyState五种状态详解
2011-07-24 14:15 1614(0) UNINITIALIZED 未初始化 The obje ... -
getElementByTagName 与 querySelectorAll
2011-07-14 11:29 1478虽然网上有中文翻译但是还是直接看英文有感觉。getElemen ... -
拖放 Drag and drop 方法
2011-07-10 18:55 1526虽然网上又很多实现方法,但是还是需要理解拖放原理。通过绑定on ... -
闭包传入参数 window & undefined
2011-07-03 08:53 2303大家在前端开发中对闭包应该和熟悉了,也就是几种常见的闭包方式: ... -
textarea光标位置插入文字
2011-06-18 18:14 2128各浏览器TextArea获得焦点后的光标位置情况: text ... -
IE6上Array不支持indexOf方法
2011-06-06 10:17 2252在IE6不支持Array上indexOf方法,又是可恶的ie, ... -
处理不支持JavaScript脚本情况
2011-05-26 10:24 1339现在主流的浏览器都支持javascrip, 但还是有小部分不支 ... -
动态创建iframe设置属性name问题
2011-04-20 13:54 2732通常iframe的name可以是link或者form的targ ... -
WebSocket and Socket.IO
2011-04-06 15:39 3464WebSocket API是下一代客户端-服务器的异步通信方法 ... -
Preload CSS/JavaScript预加载
2011-04-06 10:20 1473希望达到效果是页面第一次载入以后,如果在次刷新页或者进入下一个 ...
相关推荐
本篇文章主要聚焦于JavaScript中的一些常用属性和方法,特别是针对文档对象模型(DOM)的操作。 1. **document对象**:作为JavaScript中的全局对象,它代表了整个HTML或XML文档。例如,`document.title`用于设置或...
在深入探讨JavaScript中`document`对象的常用方法之前,我们先明确一点:`doucment`应为拼写错误,正确的关键词是`document`。`document`对象是浏览器提供的核心对象之一,它代表了当前网页文档,并提供了访问和操作...
JavaScript与HTML的交互主要通过DOM(Document Object Model)进行。熟练掌握选择元素(如`getElementById`、`querySelector`、`querySelectorAll`)、添加/删除元素、修改属性和事件处理是提高前端效率的关键。 四...
- 不要在JavaScript字符串中直接使用特殊字符编码,应使用其对应的Unicode转义序列,如`\u00A9`表示版权符号。 综上所述,理解并熟练掌握HTML特殊字符编码对于编写高质量、兼容性强的HTML文档至关重要。通过正确的...
在JavaScript中,Unicode编码通常采用UTF-16格式,其中大部分常用字符(包括汉字)由两个字节表示,而其他更复杂的字符可能需要四个字节。 二、JavaScript中的Unicode转换 在JavaScript中,有几种方法可以将汉字...
6. **防止被嵌入框架**:使用JavaScript检查当前页面是否在顶级窗口中,如果不是,则重定向到包含框架的页面。 ```javascript if (window == top) top.location.href = "frames.htm"; ``` 7. **禁止网页被另存为**...
《ArcGIS API for JavaScript 中文帮助文档与Demo详解》 ArcGIS API for JavaScript 是Esri公司提供的一款强大的JavaScript库,用于构建交互式的地理信息系统(GIS)应用。它为开发者提供了丰富的功能,包括地图...
### HTML常用编码知识点详解 #### 一、HTML简介 HTML,即HyperText Markup Language(超文本标记语言),是用于创建网页的基本标记语言。虽然HTML本身不是编程语言,但其通过一系列预定义的标签来构建和展示网页...
- HTML5中元素名和属性名不区分大小写,但有一系列编码惯例。 5. HTML5文档内容标记 - HTML5中可以使用注释来解释代码或屏蔽某些部分,使用<!--注释内容-->进行标记。 - 列表元素包括无序列表()、有序列表()...
JavaScript转义符与HTML转义符类似,但主要应用于JavaScript字符串中。在JavaScript中,反斜杠(\)用于转义特殊字符,例如"\n"表示换行,"\t"表示制表符,"\\"表示反斜杠本身,而"\'"和'\"'分别用来转义单引号和双...
5. **字符串拼接与操作**:在JavaScript中,不同编码的字符串拼接可能导致乱码。比如,一个UTF-8字符串与GBK字符串合并,如果不进行编码转换,结果可能会出错。 6. **工具配置**:开发工具,如编辑器、构建工具,...
《HTML+CSS+JavaScript网页制作案例教程(第2版)》是一本全面涵盖网页制作基础知识与实践技巧的教材。此教学大纲旨在引导学生系统学习网页设计的核心技术,通过理论讲解和实际案例,使学习者掌握网页开发的基本流程...
根据给定的文件信息,以下是对标题“javascript常用函数大全”及描述中涉及的重要知识点的详细解析: ### 基础知识:创建脚本块 #### 示例代码: ```html <script language="JavaScript"> // JavaScript代码放这里...
在JavaScript(JS)中,处理中文字符编码是一个常见的需求,特别是在与服务器交互或者处理文本数据时。GB2312编码是一种在中国大陆广泛使用的简体中文字符集,它包含了6763个常用汉字和一些其他字符。在JavaScript中...
1.4.html 使用JavaScript对网页中的内容进行验证。 1.5.html HMTL中调用.js文件。 1.6.html 使用“”标记,实现的滚动字幕效果。 1.7.html 使用JavaScript实现简单的字幕滚动。 1.8.html 使用...
在JavaScript开发中,有几个常用的功能是必不可少的,包括但不限于: 1. **变量声明**:JavaScript使用`var`, `let` 和 `const` 声明变量,其中`let` 和 `const` 是ES6引入的新特性,提供了更好的作用域管理和不可...
### JavaScript常用对象参考知识点 #### Math对象 - **E**: 欧拉常数`e`的值(大约为2.718)。 - **LN10**: 10的自然对数的值(大约为2.302)。 - **LN2**: 2的自然对数的值(大约为0.693)。 - **LOG2E**: 以2为底...
ASP编码与反编码工具是针对ASP(Active Server Pages)编程语言设计的一款专业软件,它主要用于处理ASP、JavaScript(js)、VBScript(vbs)以及HTML等文件中的编码和解码问题。这款工具对于开发和调试ASP应用程序的...
**二、字符编码与转换** 在HTML和JavaScript中,字符编码主要涉及ASCII码(American Standard Code for Information Interchange)和Unicode。ASCII码只包含128个字符,而Unicode则包含了世界上大部分语言的字符。 ...
JavaScript是一种广泛应用于网页和网络应用的编程...总之,"常用Javascript特效代码"这个压缩包是开发者学习和实践中宝贵的资源,涵盖了JavaScript特效实现的多个方面,通过深入理解和实践,可以增强开发者的前端技能。