找回密码
 注册
搜索
查看: 2092|回复: 0

JavaScript编码转换(UTF-8、UTF-16)

[复制链接]
发表于 2014-12-18 18:48:13 | 显示全部楼层 |阅读模式

        JavaScript的字符用UTF16进行编码,网页常用的编码是UTF8或者GB2312,在不涉及到字符串字节操作时,JavaScript编码和网页编码即使不一致也可以使用。但是当进行诸如Base64涉及字节之类的操作,尤其是有中文字符时,JavaScript编码的字符内容在网页中或者在服务器端显示为乱码。因此在进行字节操作时必须把JavaScript编码转成网页编码。在进行编码转换之前,先普及计算机字符编码及实现。

字符编码基础

        计算机最开始只支持ASCII码,一个字符用一个字节表示,只用了低7位,最高位为0,因此总共有128个ASCII码,范围为0~127。后来为了支持多种地区的语言,各大组织机构和IT厂商开始发明它们自己的编码方案,以便弥补ASCII编码的不足,如GB2312编码、GBK编码和Big5编码等。但这些编码都只是针对局部地区或少数语言文字,没有办法表达所有的语言文字。而且这些不同的编码之间并没有任何联系,它们之间的转换需要通过查表来实现。为了提高计算机的信息处理和交换功能,使得世界各国的文字都能在计算机中处理,从1984年起,ISO组织就开始研究制定一个全新的标准:通用多八位(即多字节)编码字符集(Universal Multiple-Octet Coded Character Set),简称UCS。标准的编号为:ISO 10646。这一标准为世界各种主要语言的字符(包括简体及繁体的中文字)及附加符号,编制统一的内码。统一码(Unicode)是Universal Code的缩写,是由另一个叫“Unicode学术学会”(The Unicode Consortium)的机构制定的字符编码系统。Unicode与ISO 10646国际编码标准从内容上来说是同步一致的。

ANSI

    ANSI不代表具体的编码,它是指本地编码。比如在简体版windows上它表示GB2312编码,在繁体版windows上它表示Big5编码,在日文操作系统上它表示JIS编码。所以如果新建了个文本文件并保存为ANSI编码,那么这个文件的编码为本地编码。

Unicode

    Unicode编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的Unicode版本对应于UCS-2,使用16位编码空间,也就是每个字符占用2个字节。这样理论上一共最多可以表示2的16次方(即65536)个字符,基本满足各种语言的使用。实际上当前版本的Unicode并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。

    Unicode编码是和字符表一一映射的。比如4EBA代表汉字'人',这种映射关系是固定不变的。通俗的说Unicode编码就是字符表的坐标,通过4EBA就能找到汉字'人'。

    Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的,但是由于不同系统平台的设计不一致,以及出于节省空间考虑,Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。UTF8、UTF16、GB2312都是Unicode编码的实现。

UTF-16

    UTF-16把Unicode字符集的抽象码位映射为16位长的整数序列,即用固定2字节存储Unicode编码。UTF-16编码是Unicode最直接的实现方式,通常我们在windows上新建文本文件后保存为Unicode编码,其实就是保存为UTF-16编码。因为是多字节存储,所以UTF-16存储方式分为2种:大端序和小端序。汉字人的Unicode编码是4EBA,以大端序存储为4E BA,以小端序存储为BA 4E,Windows和Linux使用小端序存储方式。

UTF-8

    UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,为1~6个字节。UTF-8的编码规则:

1、128个US-ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)。
2、带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码(Unicode范围由U+0080至U+07FF)。
3、其他基本多文种平面(BMP)中的字符(这包含了大部分常用字)使用三个字节编码(Unicode范围由U+0800至U+FFFF)。
4、其他极少使用的Unicode 辅助平面的字符使用四至六字节编码(Unicode范围由U+10000至U+1FFFFF使用四字节,Unicode范围由U+200000至U+3FFFFFF使用五字节,Unicode范围由U+4000000至U+7FFFFFFF使用六字节)。
GB2312

    GB2312是中华人民共和国国家标准简体中文字符集,通行于中国大陆,新加坡等地也采用此编码,中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312中对所收汉字进行了分区处理,每区含有94个汉字/符号,这种表示方式也称为区位码。

01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。

    举例来说,啊是GB2312之中的第一个汉字,它的区位码就是1601。
    GB2312通常采用EUC储存方法,以便兼容于ASCII。ASCII字符用单字节表示,汉字及符号以两个字节表示。第一个字节称为高位字节(也称区字节),第二个字节称为低位字节(也称位字节)。高位字节使用了0xA1-0xF7(把01-87区的区号加上0xA0),低位字节使用了0xA1-0xFE(把01-94加上 0xA0)。由于一级汉字从16区起始,汉字区的高位字节的范围是0xB0-0xF7,低位字节的范围是0xA1-0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。例如啊字在大多数程序中,会以两个字节0xB0(第一个字节)0xA1(第二个字节)储存。区位码=区字节+位字节(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。

UTF-16和UTF-8转换

UCS-2编码(UTF-16)UTF-8二进制字节流
0000 - 007F0xxxxxxx
0080 - 07FF110xxxxx  10xxxxxx
0800 - FFFF1110xxxx  10xxxxxx  10xxxxxx

  1. //UTF-16转UTF-8
  2. function utf16ToUtf8(s){
  3.         if(!s){
  4.                 return;
  5.         }
  6.        
  7.         var i, code, ret = [], len = s.length;
  8.         for(i = 0; i < len; i++){
  9.                 code = s.charCodeAt(i);
  10.                 if(code > 0x0 && code <= 0x7f){
  11.                         //单字节
  12.                         //UTF-16 0000 - 007F
  13.                         //UTF-8  0xxxxxxx
  14.                         ret.push(s.charAt(i));
  15.                 }else if(code >= 0x80 && code <= 0x7ff){
  16.                         //双字节
  17.                         //UTF-16 0080 - 07FF
  18.                         //UTF-8  110xxxxx 10xxxxxx
  19.                         ret.push(
  20.                                 //110xxxxx
  21.                                 String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)),
  22.                                 //10xxxxxx
  23.                                 String.fromCharCode(0x80 | (code & 0x3f))
  24.                         );
  25.                 }else if(code >= 0x800 && code <= 0xffff){
  26.                         //三字节
  27.                         //UTF-16 0800 - FFFF
  28.                         //UTF-8  1110xxxx 10xxxxxx 10xxxxxx
  29.                         ret.push(
  30.                                 //1110xxxx
  31.                                 String.fromCharCode(0xe0 | ((code >> 12) & 0xf)),
  32.                                 //10xxxxxx
  33.                                 String.fromCharCode(0x80 | ((code >> 6) & 0x3f)),
  34.                                 //10xxxxxx
  35.                                 String.fromCharCode(0x80 | (code & 0x3f))
  36.                         );
  37.                 }
  38.         }
  39.        
  40.         return ret.join('');
  41. }
  42. //UTF-8转UTF-16
  43. function utf8ToUtf16(s){
  44.         if(!s){
  45.                 return;
  46.         }
  47.        
  48.         var i, codes, bytes, ret = [], len = s.length;
  49.         for(i = 0; i < len; i++){
  50.                 codes = [];
  51.                 codes.push(s.charCodeAt(i));
  52.                 if(((codes[0] >> 7) & 0xff) == 0x0){
  53.                         //单字节  0xxxxxxx
  54.                         ret.push(s.charAt(i));
  55.                 }else if(((codes[0] >> 5) & 0xff) == 0x6){
  56.                         //双字节  110xxxxx 10xxxxxx
  57.                         codes.push(s.charCodeAt(++i));
  58.                         bytes = [];
  59.                         bytes.push(codes[0] & 0x1f);
  60.                         bytes.push(codes[1] & 0x3f);
  61.                         ret.push(String.fromCharCode((bytes[0] << 6) | bytes[1]));
  62.                 }else if(((codes[0] >> 4) & 0xff) == 0xe){
  63.                         //三字节  1110xxxx 10xxxxxx 10xxxxxx
  64.                         codes.push(s.charCodeAt(++i));
  65.                         codes.push(s.charCodeAt(++i));
  66.                         bytes = [];
  67.                         bytes.push((codes[0] << 4) | ((codes[1] >> 2) & 0xf));
  68.                         bytes.push(((codes[1] & 0x3) << 6) | (codes[2] & 0x3f));                       
  69.                         ret.push(String.fromCharCode((bytes[0] << 8) | bytes[1]));
  70.                 }
  71.         }
  72.         return ret.join('');
  73. }
复制代码


您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2025-6-19 03:49 , Processed in 0.015299 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表