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

        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 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx  10xxxxxx
0800 - FFFF 1110xxxx  10xxxxxx  10xxxxxx

//UTF-16转UTF-8
function utf16ToUtf8(s){
	if(!s){
		return;
	}
	
	var i, code, ret = [], len = s.length;
	for(i = 0; i < len; i++){
		code = s.charCodeAt(i);
		if(code > 0x0 && code <= 0x7f){
			//单字节
			//UTF-16 0000 - 007F
			//UTF-8  0xxxxxxx
			ret.push(s.charAt(i));
		}else if(code >= 0x80 && code <= 0x7ff){
			//双字节
			//UTF-16 0080 - 07FF
			//UTF-8  110xxxxx 10xxxxxx
			ret.push(
				//110xxxxx
				String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)),
				//10xxxxxx
				String.fromCharCode(0x80 | (code & 0x3f))
			);
		}else if(code >= 0x800 && code <= 0xffff){
			//三字节
			//UTF-16 0800 - FFFF
			//UTF-8  1110xxxx 10xxxxxx 10xxxxxx
			ret.push(
				//1110xxxx
				String.fromCharCode(0xe0 | ((code >> 12) & 0xf)),
				//10xxxxxx
				String.fromCharCode(0x80 | ((code >> 6) & 0x3f)),
				//10xxxxxx
				String.fromCharCode(0x80 | (code & 0x3f))
			);
		}
	}
	
	return ret.join('');
}
//UTF-8转UTF-16
function utf8ToUtf16(s){
	if(!s){
		return;
	}
	
	var i, codes, bytes, ret = [], len = s.length;
	for(i = 0; i < len; i++){
		codes = [];
		codes.push(s.charCodeAt(i));
		if(((codes[0] >> 7) & 0xff) == 0x0){
			//单字节  0xxxxxxx
			ret.push(s.charAt(i));
		}else if(((codes[0] >> 5) & 0xff) == 0x6){
			//双字节  110xxxxx 10xxxxxx
			codes.push(s.charCodeAt(++i));
			bytes = [];
			bytes.push(codes[0] & 0x1f);
			bytes.push(codes[1] & 0x3f);
			ret.push(String.fromCharCode((bytes[0] << 6) | bytes[1]));
		}else if(((codes[0] >> 4) & 0xff) == 0xe){
			//三字节  1110xxxx 10xxxxxx 10xxxxxx
			codes.push(s.charCodeAt(++i));
			codes.push(s.charCodeAt(++i));
			bytes = [];
			bytes.push((codes[0] << 4) | ((codes[1] >> 2) & 0xf));
			bytes.push(((codes[1] & 0x3) << 6) | (codes[2] & 0x3f));			
			ret.push(String.fromCharCode((bytes[0] << 8) | bytes[1]));
		}
	}
	return ret.join('');
}


你可能感兴趣的:(JavaScript)