Linux.中国 - 开源社区

 找回密码
 骑士注册

QQ登录

微博登录


编码 unicode 及其在 javascript 中的使用

2014-9-5 10:14    评论: 1 分享: 4    

三、UTF-8 编码

由于 unicode 编码的前 128 位是ASCII 码,他们已经包含大部分西欧语言的字符,而且只要一个字节就可以全部编号了,还多出来 128 个空位,8位2进制,其实只使用了7位,第8位被设置为0,事实上,电子邮件使用的base64编码就认为第8位是1的的字符编码都是传输错误。

对于西欧语言来说,所有字符都使用 2个字节来标记太浪费计算机内存了,于是有了UTF-7、UTF-8 等变长编码方式,其中 UTF-8 又称万国码,使用最广泛,现在已经标准化为RFC 3629。

UTF-8的编码规则有二条:

1) 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

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

因为多字节字符编码要使用前置标记位,UFT-8 对汉字的编码可能会超出2个字节达到3个字节,更少用的字符可能达到4个字节的编码。

下表是UTF-8 编码的码位分布情况,其中的 x 表示字符的 unicode 二进制编码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编码十六进制格式是 E596B5,把他们转换二进制:

parseInt('E5',16).toString(2) // 11100101
parseInt('96',16).toString(2) // 10010110
parseInt('B5',16).toString(2) // 10110101

因此 它的 UTF-8 二进制编码为 11100101 10010110 10110101,其中的 二进制 unicode 编码就是 01010101 10110101。

转换为 16进制编码格式就是 

parseInt('0101010110110101',2).toString(16) //55b5

因此它的 unicode-16 的16进制编码是 55b5 ,试打印出来

document.write('\u55b5'); // 喵

四、 URL 编码函数: escape(已经不推荐使用) 、encodeURI、encodeURIComponent

这些函数不会对 ASCII 字母和数字进行编码,但会对一些特殊符号和多字节字符进行16进制编码,其中 escape 使用unicode-16 编码,encodeURI、encodeURIComponent 使用 UTF-8编码。

他们对 单字节 ASCII 特殊符号编码结果都是一样的,格式是 % + 2位16进制编码,例如空格被编码为 %20。对于多字节字符,escape 的编码格式为 %u + unicode 十六进制双字节编码( 如果是单字节字符则是 % + unicode + 十六进制编码),而 encodeURI、encodeURIComponent 则是在字符的每个 UTF-8 编码字节前加 % ,例如 汉字 '喵' 的编码分别是:

escape('喵'); // %u55B5
encodeURI('喵'); // %E5%96%B5
encodeURIComponent('喵'); // %E5%96%B5

encodeURI、encodeURIComponent 的区别是:

encodeURI 不对在URL 上使用的特殊含义的字符编码,如 ;/?:@&=+$,# , 所以你可以使用 encodeURI 对一个URL编码后仍能正确使用它访问网络资源或文件目录。

encodeURIComponent 的编码对象是 url 上的组件,例如附加参数,他会对 ;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号 进行编码,因此不应该使用它对整个 URL 进行编码。

五、字符实体中的 unicode

HTML 字符实体可以直接用于HTML文件中,写法为 '&#' +unicode 编码的十进制数字 + ';',或者 '&#x' +unicode 编码的十六进制数字 + ';',如 大于号 > 的字符实体 为 > 或者 > 高位可以不补0,也可以写成 >

(62).toString(16) //3e
document.write('>'); // 打印出 大于号 >

下面是HTML中常用的字符实体表,其中只有少部分有专门用于 HTML 文件输出的实体名,任何 unicode-16 字符都可以通过字符实体在 HTML 文件中打印出来。 http://www.w3school.com.cn/tags/html_ref_entities.html  。

六、正则表达式中的 unicode 编码

var str = 'asd乃阿当123安迪asd123啊那的';
str.match(/[\u0000-\u00ff]/g); //单字节字符
//["a", "s", "d", "1", "2", "3", "a", "s", "d", "1", "2", "3"]

str.match(/[\x00-\xff]/g); //单字节字符
//["a", "s", "d", "1", "2", "3", "a", "s", "d", "1", "2", "3"]

str.match(/[\u0100-\uffff]/g); //双字节字符
//["乃", "阿", "当", "安", "迪", "啊", "那", "的"]

七、大端通讯、小端通讯和BOM(Byte Order Mark)

在数据通讯中传输数据时,可以采用两种数据传输方式:高位在前(大端,big endian)或高位在后(小端,little endian)。例如汉字'喵' 的unicode 16进制编码为 16进制数 0x55B5 ,传输方式:

大端通讯:0x55 0xB5
小端通讯:0xB5 0x55

BOM 是针对单个字符的本身的多字节编码而言的,如果字符的编码都是使用一个字节来编码则不存在字节序的问题,例如 ASCII 编码就不会存在字节序问题。 

接收的二进制数据按每8位1字节,每字节使用2个十六进制字符编码为 unicode 后,存在一个问题,如何区别是高位在前还是高位在后。

Unicode规范中有一个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且,编码为FFFE 的字符在 unicode 中不存在,因此在存储文件或在网络传输字节流时,可以用这个字符来标记大端通讯和小端通讯。

UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。

在存储文件时,如果一个文本文件的头两个字节是FE FF,就表示该文件采用大端方式;如果头两个字节是FF FE,就表示该文件采用小端方式。

由于UTF-8 多字节编码方式定义其第一个字节的前几位使用 1 来声明该字符占多少个字节,因此,UTF-8编码方式不存在编码字节顺序的问题,但是仍然可以给 UTF-8 字节数据加上大端小端标记(带BOM 的UTF-8 编码格式)。 BOM 对于 UTF-8 格式文件是没实用意义的,因此一般推荐保存为不带 BOM 的UTF-8 格式。

javascript 的类型数组在读取二进制数据(BLOB)时,是以 小端方式存入数组的,相关资料参考下面: http://www.cnblogs.com/ecalf/archive/2012/11/25/2787219.html 

关于BOM ,可访问下面链接进一步了解:http://www.cppblog.com/colorful/archive/2012/05/17/175182.html  

八、中文编码 GB2312 、GBK、BIG5

这些编码不是unicode 编码而是区位码和汉字内码,这些编码前一个字节仍然兼容ASCII,GB2312(简体) 、GBK(简繁体)由中国大陆机构编撰,BIG5(繁体)由港奥台相关机构和计算机厂商编撰,区位码在 windows 平台使用的代码页转换表(CodePage)映射到 unicode 编码。

代码页技术现在已经广泛为各种平台所采用。UTF-7的代码页是65000,UTF-8的代码页是65001。

九、维基百科中关于 utf-16 代理码对算法的描述:

从U+10000到U+10FFFF的码位

辅助平面(Supplementary Planes)中的码位,在UTF-16中被编码为一对16比特长的码元(即32bit,4Bytes),称作 code units called a 代理对(surrogate pair), 具体方法是:

  • 码位减去0x10000, 得到的值的范围为20比特长的0..0xFFFFF.
  • 高位的10比特的值(值的范围为0..0x3FF)被加上0xD800得到第一个码元或称作高位代理(high surrogate), 值的范围是0xD800..0xDBFF. 由于高位代理比低位代理的值要小,所以为了避免混淆使用,Unicode标准现在称高位代理为前导代理(lead surrogates).
  • 低位的10比特的值(值的范围也是0..0x3FF)被加上0xDC00得到第二个码元或称作低位代理(low surrogate), 现在值的范围是0xDC00..0xDFFF. 由于低位代理比高位代理的值要大,所以为了避免混淆使用,Unicode标准现在称低位代理为后尾代理(trail surrogates).
UTF-16解码
lead \ trail DC00DC01   …   DFFF
D800 10000 10001 103FF
D801 10400 10401 107FF
  ⋮
DBFF 10FC00 10FC01 10FFFF

由于高位代理、低位代理、BMP中的有效字符的码位,三者互不重叠,搜索是简单的: 一个字符编码的一部分不可能与另一个字符编码的不同部分相重叠。这意味着UTF-16是自同步(self-synchronizing): 可以通过仅检查一个码元就可以判定给定字符的下一个字符的起始码元。

计算过程:

12
查看其它分页:

发表评论


最新评论

我也要发表评论

陈伟琪在肇庆 2014-9-5 12:33  新浪微博网友评论
实用文章!
回复
返回顶部

分享到微信朋友圈

打开微信,点击底部的“发现”,
使用“扫一扫”将网页分享至朋友圈。