文档章节

JavaScript: 详解Base64编码和解码

陈亦
 陈亦
发布于 2014/02/19 06:22
字数 3438
阅读 16949
收藏 334

Base64是最常用的编码之一,比如开发中用于传递参数、现代浏览器中的<img />标签直接通过Base64字符串来渲染图片以及用于邮件中等等。Base64编码在RFC2045中定义,它被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。

我们知道,任何数据在计算机中都是以二进制的方式存储的。一个字节为8位,一个字符在计算机中存储为一个或多个字节,比如英文字母、数字以及英文标点符号就是用一个 字节来存储的,通常称为ASCII码。而简体中文、繁体中文、日文以及韩文等都是用多字节来存储的,通常称为多字节字符。因为Base64编码是对字符串的编码表示进行处理的,不同编码的字符串的Base64的结果是不同的,所以我们需要了解基本的字符编码知识。

字符编码基础

计算机最开始只支持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国际编码标准从内容上来说是同步一致的。具体可参考:Unicode 。

ANSI

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

Unicode

Unicode编码是和字符表一一映射的。比如56DE代表汉字'回',这种映射关系是固定不变的。通俗的说Unicode编码就是字符表的坐标,通过56DE就能找到汉字'回'。Unicode编码的实现包括UTF8、UTF16、UTF32等等。

Unicode本身定义的就是每个字符的数值,是字符和自然数的映射关系,而UTF-8或者UTF-16甚至UTF-32则定义了如何在字节流中断字,是计算机领域的概念。

通过上图我们知道,UTF-8编码为变长的编码方式,占1~6个字节,可通过Unicode编码值的区间来判断,并且每个组成UTF8字符的字节都是有规律可循的。本文只讨论UTF8和UTF16这两种编码。

UTF16

UTF16编码使用固定的2个字节来存储。因为是多字节存储,所以它的存储方式分为2种:大端序和小端序。UTF16编码是Unicode最直接的实现方式,通常我们在windows上新建文本文件后保存为Unicode编码,其实就是保存为UTF16编码。UTF16编码在windows上采用小端序的方式存储,以下我新建了个文本文件并保存为Unicode编码来测试,文件中只输入了一个汉字'回',之后我用Editplus打开它,切换到十六进制方式查看,如图所示:

我们看到有4个字节,前2个字节FF FE是文件头,表示这是一个UTF16编码的文件,而DE 56则是'回'的UTF16编码的十六进制。我们经常使用的JavaScript语言,它内部就是采用UTF16编码,并且它的存储方式为大端序,来看一个例子:

<script type="text/javascript">
console.group('Test Unicode: ');
console.log(('回'.charCodeAt(0)).toString(16).toUpperCase());
</script>

 

很明显跟刚才Editplus显示的不一样,顺序是相反的,这是因为字节序不一样。具体可参考:UTF-16

UTF8

UTF8是采用变长的编码方式,为1~6个字节,但通常我们只把它看作单字节或三字节的实现,因为其它情况实在少见。UTF8编码通过多个字节组合的方式来显示,这是计算机处理UTF8的机制,它是无字节序之分的,并且每个字节都非常有规律,详见上图,在此不再详述。

UTF16和UTF8的相互转换

UTF16转UTF8

UTF16和UTF8之间的相互转换可以通过上图的转换表来实现,判断Unicode码所在的区间就可以得到这个字符是由几个字节所组成,之后通过移位来实现。我们用汉字'回'来举一个转换的例子。

我们已经知道汉字'回'的Unicode码是0x56DE,它介于U+00000800 – U+0000FFFF之间,所以它是用三个字节来表示的。

所以我们需要将0x56DE这个双字节的值变为三字节的值,注意上图中的x部分,就是对应0x56DE的各位字节,如果您数一下x的个数,会发现刚好是16位。

转换思路

从0x56DE中取出4位放在低位,并和二进制的1110结合,这就是第一个字节。从0x56DE中剩下的字节中取出6位放在低位,并和二进制的10结合,这就是第二个字节。第三个字节依照类似的方式实现。

代码实现

为了让大家更好的理解,以下代码只是实现汉字'回'的转换,代码如下:

<script type="text/javascript">
/**
* 转换对照表
* 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
*/
/*
* '回'的Unicode编码为:0x56DE,它介于U+00000800 – U+0000FFFF之间,所以它占用三个字节。
* U+00000800 – U+0000FFFF 	1110xxxx 10xxxxxx 10xxxxxx
*/
var ucode = 0x56DE;
// 1110xxxx
var byte1 = 0xE0 | ((ucode >> 12) & 0x0F);
// 10xxxxxx
var byte2 = 0x80 | ((ucode >> 6) & 0x3F);
// 10xxxxxx
var byte3 = 0x80 | (ucode & 0x3F);
var utf8 = String.fromCharCode(byte1)
		+ String.fromCharCode(byte2)
		+ String.fromCharCode(byte3);

console.group('Test UTF16ToUTF8: ');
console.log(utf8);
console.groupEnd();
</script>

 

输出的结果看起来像乱码,这是因为JavaScript不知道如何显示UTF8的字符。您或许会说输出不正常转换还有什么用,但您应该知道转换的目的还经常用于传输或API的需要。

UTF8转UTF16

这是UTF16转换到UTF8的逆转换,同样需要对照转换表来实现。还是接上一个例子,我们已经得到了汉字'回'的UTF8编码,这是三个字节的,我们只需要按照转换表来转成双字节的,如图所示,我们需要保留下所有的x。

代码如下:

<script type="text/javascript">
/**
* 转换对照表
* 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
*/
/*
* '回'的Unicode编码为:0x56DE,它介于U+00000800 – U+0000FFFF之间,所以它占用三个字节。
* U+00000800 – U+0000FFFF 	1110xxxx 10xxxxxx 10xxxxxx
*/
var ucode = 0x56DE;
// 1110xxxx
var byte1 = 0xE0 | ((ucode >> 12) & 0x0F);
// 10xxxxxx
var byte2 = 0x80 | ((ucode >> 6) & 0x3F);
// 10xxxxxx
var byte3 = 0x80 | (ucode & 0x3F);
var utf8 = String.fromCharCode(byte1)
		+ String.fromCharCode(byte2)
		+ String.fromCharCode(byte3);

console.group('Test UTF16ToUTF8: ');
console.log(utf8);
console.groupEnd();
/** ------------------------------------------------------------------------------------*/
// 由三个字节组成,所以分别取出
var c1 = utf8.charCodeAt(0);
var c2 = utf8.charCodeAt(1);
var c3 = utf8.charCodeAt(2);
/*
* 需要通过判断特定位的方式来转换,但这里是已知是三个字节,所以忽略判断,而是直接拿到所有的x,组成16位。
* U+00000800 – U+0000FFFF 	1110xxxx 10xxxxxx 10xxxxxx
*/
// 丢弃第一个字节的高四位并和第二个字节的高四位组成一个字节
var b1 = (c1 << 4) | ((c2 >> 2) & 0x0F);
// 同理第二个字节和第三个字节组合
var b2 = ((c2 & 0x03) << 6) | (c3 & 0x3F);
// 将b1和b2组成16位
var ucode = ((b1 & 0x00FF) << 8) | b2;
console.group('Test UTF8ToUTF16: ');
console.log(ucode.toString(16).toUpperCase(), String.fromCharCode(ucode));
console.groupEnd();
</script>

 

知道了转换规则,就很容易实现了。

Base64编码

Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。由于2的6次方为64,所以每6个位为一个单元,对应某个可打印字符。当原数据不是3的整数倍时,如果最后剩下两个输入数据,在编码结果后加1个“=;如果最后剩下一个输入数据,编码结果后加2个“=;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

转码对照表

每6个单元高位补2个零形成的字节位于0~63之间,通过在转码表中查找对应的可打印字符。“=”用于填充。如下图所示为转码表。

具体可参考: Base64

Base64解码

解码是编码的逆过程,先看后面补了几个“=”号,最多只可能补2个“=”号。一个“=”相当于补了2个0,所以去掉后面补的0后,再按8位展开,即可还原。

JavaScript实现Base64的编码和解码

之前已经详细讲解了整个过程,本文的例子都是采用UTF8编码的字符串作为Base64编码的基础。因为JavaScript内部是使用Unicode编码,所以需要有个转换过程,原理之前也详细讲解过并给出了示例,以下是代码实现:

<script type="text/javascript">
/**
* UTF16和UTF8转换对照表
* 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
*/
var Base64 = {
	// 转码表
	table : [
			'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', '+', '/'
	],
	UTF16ToUTF8 : function(str) {
		var res = [], len = str.length;
		for (var i = 0; i < len; i++) {
			var code = str.charCodeAt(i);
			if (code > 0x0000 && code <= 0x007F) {
				// 单字节,这里并不考虑0x0000,因为它是空字节
				// U+00000000 – U+0000007F 	0xxxxxxx
				res.push(str.charAt(i));
			} else if (code >= 0x0080 && code <= 0x07FF) {
				// 双字节
				// U+00000080 – U+000007FF 	110xxxxx 10xxxxxx
				// 110xxxxx
				var byte1 = 0xC0 | ((code >> 6) & 0x1F);
				// 10xxxxxx
				var byte2 = 0x80 | (code & 0x3F);
				res.push(
					String.fromCharCode(byte1), 
					String.fromCharCode(byte2)
				);
			} else if (code >= 0x0800 && code <= 0xFFFF) {
				// 三字节
				// U+00000800 – U+0000FFFF 	1110xxxx 10xxxxxx 10xxxxxx
				// 1110xxxx
				var byte1 = 0xE0 | ((code >> 12) & 0x0F);
				// 10xxxxxx
				var byte2 = 0x80 | ((code >> 6) & 0x3F);
				// 10xxxxxx
				var byte3 = 0x80 | (code & 0x3F);
				res.push(
					String.fromCharCode(byte1), 
					String.fromCharCode(byte2), 
					String.fromCharCode(byte3)
				);
			} else if (code >= 0x00010000 && code <= 0x001FFFFF) {
				// 四字节
				// U+00010000 – U+001FFFFF 	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
			} else if (code >= 0x00200000 && code <= 0x03FFFFFF) {
				// 五字节
				// U+00200000 – U+03FFFFFF 	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
			} else /** if (code >= 0x04000000 && code <= 0x7FFFFFFF)*/ {
				// 六字节
				// U+04000000 – U+7FFFFFFF 	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
			}
		}

		return res.join('');
	},
	UTF8ToUTF16 : function(str) {
		var res = [], len = str.length;
		var i = 0;
		for (var i = 0; i < len; i++) {
			var code = str.charCodeAt(i);
			// 对第一个字节进行判断
			if (((code >> 7) & 0xFF) == 0x0) {
				// 单字节
				// 0xxxxxxx
				res.push(str.charAt(i));
			} else if (((code >> 5) & 0xFF) == 0x6) {
				// 双字节
				// 110xxxxx 10xxxxxx
				var code2 = str.charCodeAt(++i);
				var byte1 = (code & 0x1F) << 6;
				var byte2 = code2 & 0x3F;
				var utf16 = byte1 | byte2;
				res.push(Sting.fromCharCode(utf16));
			} else if (((code >> 4) & 0xFF) == 0xE) {
				// 三字节
				// 1110xxxx 10xxxxxx 10xxxxxx
				var code2 = str.charCodeAt(++i);
				var code3 = str.charCodeAt(++i);
				var byte1 = (code << 4) | ((code2 >> 2) & 0x0F);
				var byte2 = ((code2 & 0x03) << 6) | (code3 & 0x3F);
				var utf16 = ((byte1 & 0x00FF) << 8) | byte2
				res.push(String.fromCharCode(utf16));
			} else if (((code >> 3) & 0xFF) == 0x1E) {
				// 四字节
				// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
			} else if (((code >> 2) & 0xFF) == 0x3E) {
				// 五字节
				// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
			} else /** if (((code >> 1) & 0xFF) == 0x7E)*/ {
				// 六字节
				// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
			}
		}

		return res.join('');
	},
	encode : function(str) {
		if (!str) {
			return '';
		}
		var utf8    = this.UTF16ToUTF8(str); // 转成UTF8
		var i = 0; // 遍历索引
		var len = utf8.length;
		var res = [];
		while (i < len) {
			var c1 = utf8.charCodeAt(i++) & 0xFF;
			res.push(this.table[c1 >> 2]);
			// 需要补2个=
			if (i == len) {
				res.push(this.table[(c1 & 0x3) << 4]);
				res.push('==');
				break;
			}
			var c2 = utf8.charCodeAt(i++);
			// 需要补1个=
			if (i == len) {
				res.push(this.table[((c1 & 0x3) << 4) | ((c2 >> 4) & 0x0F)]);
				res.push(this.table[(c2 & 0x0F) << 2]);
				res.push('=');
				break;
			}
			var c3 = utf8.charCodeAt(i++);
			res.push(this.table[((c1 & 0x3) << 4) | ((c2 >> 4) & 0x0F)]);
			res.push(this.table[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)]);
			res.push(this.table[c3 & 0x3F]);
		}

		return res.join('');
	},
	decode : function(str) {
		if (!str) {
			return '';
		}

		var len = str.length;
		var i   = 0;
		var res = [];

		while (i < len) {
			code1 = this.table.indexOf(str.charAt(i++));
			code2 = this.table.indexOf(str.charAt(i++));
			code3 = this.table.indexOf(str.charAt(i++));
			code4 = this.table.indexOf(str.charAt(i++));

			c1 = (code1 << 2) | (code2 >> 4);
			res.push(String.fromCharCode(c1));

			if (code3 != -1) {
				c2 = ((code2 & 0xF) << 4) | (code3 >> 2);
				res.push(String.fromCharCode(c2));
			}
			if (code4 != -1) {
				c3 = ((code3 & 0x3) << 6) | code4;
				res.push(String.fromCharCode(c3));
			}

		}

		return this.UTF8ToUTF16(res.join(''));
	}
};

var msg = 'Hello, oschina!又是一年春来到~!';
console.group('Test Base64: ');
var b64 = Base64.encode(msg);
console.log(b64);

d64 = Base64.decode(b64);
console.log(d64, d64 === msg);
console.groupEnd();
</script>

 

不得不说,在JavaScript中实现确实很麻烦。我们来看下PHP对同样的字符串编码的结果:

因为字符编码是一样的,所以结果也一样。

© 著作权归作者所有

共有 人打赏支持
陈亦
粉丝 237
博文 23
码字总数 53194
作品 0
浦东
高级程序员
私信 提问
加载中

评论(27)

陈亦
陈亦

引用来自“Igin”的评论

利用自带的btoa,atob,escape,unescape,encodeURIComponent,decodeURIComponent是最简单的。

decodeURIComponent(escape(atob("SGVsbG8sIG9zY2hpbmHvvIHlj4jmmK/kuIDlubTmmKXmnaXliLB+")))
即可得到 "Hello, oschina!又是一年春来到~"

btoa(unescape(encodeURIComponent('Hello, oschina!又是一年春来到~')))
即可得到 "SGVsbG8sIG9zY2hpbmHvvIHlj4jmmK/kuIDlubTmmKXmnaXliLB+"
才知道有atob和btoa这样的方法,应该是新增的方法吧?
Igin
Igin
利用自带的btoa,atob,escape,unescape,encodeURIComponent,decodeURIComponent是最简单的。

decodeURIComponent(escape(atob("SGVsbG8sIG9zY2hpbmHvvIHlj4jmmK/kuIDlubTmmKXmnaXliLB+")))
即可得到 "Hello, oschina!又是一年春来到~"

btoa(unescape(encodeURIComponent('Hello, oschina!又是一年春来到~')))
即可得到 "SGVsbG8sIG9zY2hpbmHvvIHlj4jmmK/kuIDlubTmmKXmnaXliLB+"
leeqj
leeqj
不错!
帖子列表
帖子列表

引用来自“喻恒春”的评论

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

UTF16ToUTF8 函数可以用 unescape( encodeURIComponent(str) ); 代替
UTF8ToUTF16 函数可以用 decodeURIComponent( escape(str) ); 代替
这样不就省了很多代码啦、、不知道这样做有没有不严谨的地方、、

用encodeURIComponent这些函数确实是可以的,因为它们也是会转成UTF8。但是这些函数对些字符是不转义的,这就导致encodeURIComponent的结果是字符跟十六进制(带%替换成0x)混在一起,这个需要手动处理的。

还有个 unescape 呢,,你可以先测试下,结果应该和你的那个一样、
这个代码是从CryptoJS里拿出来的、

这就更不对了。首先unescape是escape的逆操作,也就是说unescape是将UTF8转回Unicode,而且unescape跟encodeURIComponent不是一对的。

可是我测试了一些数据,和你的结果完全一致,本人水平有限,希望您能帮忙测试下,看看有什么例外的情况、

unescape和escape已经被新的标准废弃, encodeURIComponent 或者 encodeURI 这些函数也能用于base64 过程, 代码上有些差异而已, 对于转 base64 还是 charCodeAt 这样的函数来的直接. 楼主的代码中增值的是转UTF8.
这里有另一个单纯 base64 的代码: https://github.com/michael/github/blob/master/lib/base64.js
推荐这个是因为里面 isNaN 的用法非常好. 值得学习.

好!
喻恒春
喻恒春

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

UTF16ToUTF8 函数可以用 unescape( encodeURIComponent(str) ); 代替
UTF8ToUTF16 函数可以用 decodeURIComponent( escape(str) ); 代替
这样不就省了很多代码啦、、不知道这样做有没有不严谨的地方、、

用encodeURIComponent这些函数确实是可以的,因为它们也是会转成UTF8。但是这些函数对些字符是不转义的,这就导致encodeURIComponent的结果是字符跟十六进制(带%替换成0x)混在一起,这个需要手动处理的。

还有个 unescape 呢,,你可以先测试下,结果应该和你的那个一样、
这个代码是从CryptoJS里拿出来的、

这就更不对了。首先unescape是escape的逆操作,也就是说unescape是将UTF8转回Unicode,而且unescape跟encodeURIComponent不是一对的。

可是我测试了一些数据,和你的结果完全一致,本人水平有限,希望您能帮忙测试下,看看有什么例外的情况、

unescape和escape已经被新的标准废弃, encodeURIComponent 或者 encodeURI 这些函数也能用于base64 过程, 代码上有些差异而已, 对于转 base64 还是 charCodeAt 这样的函数来的直接. 楼主的代码中增值的是转UTF8.
这里有另一个单纯 base64 的代码: https://github.com/michael/github/blob/master/lib/base64.js
推荐这个是因为里面 isNaN 的用法非常好. 值得学习.
楼教主
楼教主

引用来自“陈一回”的评论

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

UTF16ToUTF8 函数可以用 unescape( encodeURIComponent(str) ); 代替
UTF8ToUTF16 函数可以用 decodeURIComponent( escape(str) ); 代替
这样不就省了很多代码啦、、不知道这样做有没有不严谨的地方、、

用encodeURIComponent这些函数确实是可以的,因为它们也是会转成UTF8。但是这些函数对些字符是不转义的,这就导致encodeURIComponent的结果是字符跟十六进制(带%替换成0x)混在一起,这个需要手动处理的。

还有个 unescape 呢,,你可以先测试下,结果应该和你的那个一样、
这个代码是从CryptoJS里拿出来的、

这就更不对了。首先unescape是escape的逆操作,也就是说unescape是将UTF8转回Unicode,而且unescape跟encodeURIComponent不是一对的。

可是我测试了一些数据,和你的结果完全一致,本人水平有限,希望您能帮忙测试下,看看有什么例外的情况、
陈亦
陈亦

引用来自“乱码.”的评论

引用来自“陈一回”的评论

引用来自“乱码.”的评论

UTF16ToUTF8 函数可以用 unescape( encodeURIComponent(str) ); 代替
UTF8ToUTF16 函数可以用 decodeURIComponent( escape(str) ); 代替
这样不就省了很多代码啦、、不知道这样做有没有不严谨的地方、、

用encodeURIComponent这些函数确实是可以的,因为它们也是会转成UTF8。但是这些函数对些字符是不转义的,这就导致encodeURIComponent的结果是字符跟十六进制(带%替换成0x)混在一起,这个需要手动处理的。

还有个 unescape 呢,,你可以先测试下,结果应该和你的那个一样、
这个代码是从CryptoJS里拿出来的、

这就更不对了。首先unescape是escape的逆操作,也就是说unescape是将UTF8转回Unicode,而且unescape跟encodeURIComponent不是一对的。
楼教主
楼教主

引用来自“陈一回”的评论

引用来自“乱码.”的评论

UTF16ToUTF8 函数可以用 unescape( encodeURIComponent(str) ); 代替
UTF8ToUTF16 函数可以用 decodeURIComponent( escape(str) ); 代替
这样不就省了很多代码啦、、不知道这样做有没有不严谨的地方、、

用encodeURIComponent这些函数确实是可以的,因为它们也是会转成UTF8。但是这些函数对些字符是不转义的,这就导致encodeURIComponent的结果是字符跟十六进制(带%替换成0x)混在一起,这个需要手动处理的。

还有个 unescape 呢,,你可以先测试下,结果应该和你的那个一样、
这个代码是从CryptoJS里拿出来的、
帖子列表
帖子列表

引用来自“陈一回”的评论

引用来自“我喜欢吴佳旻”的评论

请问既然base64有/之类的问题, 那转换为url最简单的方式还有什么

Base64不是为了URI编码而生的,它最早是用于邮件中。JavaScript中一般用encodeURI来编码URL。具体可以看下URI编码:http://zh.wikipedia.org/wiki/URI

谢谢
陈亦
陈亦

引用来自“我喜欢吴佳旻”的评论

请问既然base64有/之类的问题, 那转换为url最简单的方式还有什么

Base64不是为了URI编码而生的,它最早是用于邮件中。JavaScript中一般用encodeURI来编码URL。具体可以看下URI编码:http://zh.wikipedia.org/wiki/URI
小程序(一) base64 文字编码解码以及图片编码

一、文字编码以及解码   1、小程序util.js公共js中封装的方法 /* base64编码(编码,配合encodeURIComponent使用) @parm : str 传入的字符串 使用: */function base64_encode(str) {//下面...

时光不老,我们不散
08/15
0
0
通过data:image/png;base64把图片直接写在src里

关于用base64存储图片 网页上有些图片的src或css背景图片的url后面跟了一大串字符,比如:data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAAGXRFWHRTb2Z0d2FyZQBBZ...

AsheNull
2013/10/18
0
0
基于Nodejs的微信消息加密与解密实现概要

微信团队提供了多种语言的示例代码,但不包含Nodejs实现版本。经过大量查证和尝试,我已完成并测试通过,下面说说实现要点。 准备 Nodejs为版或版,当前最新稳定版。 平台支持Windows和Linux...

一点灵犀
2015/04/08
0
2
将文件编码成base64通过AJAX上传

使用AJAX是无法直接上传文件的,一般都是新建个iframe在它里面完成表单提交的过程以达到异步上传文件的效果。 如此做可以达到比较好的浏览器兼容性,不过代码量会比较大,即使是使用了文件上...

得意小生
2015/08/02
0
4
技术讨论 记一次Node.Js反序列化攻击测试

        严正声明:本文仅限于技术讨论,严禁用于其他用途。   Node.js是一个Javascript运行时环境。它封装了GoogleV8引擎,该引擎可以高效地执行Javascript。另外,Node.js还进行了...

FreeBuf
08/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

PHP生成CSV之内部换行

当我们使用PHP将采集到的文件内容保存到csv文件时,往往需要将采集内容进行二次过滤处理才能得到需要的内容。比如网页中的换行符,空格符等等。 对于空格等处理起来都比较简单,这里我们单独...

豆花饭烧土豆
今天
1
0
使用 mjml 生成 thymeleaf 邮件框架模板

发邮件算是系统开发的一个基本需求了,不过搞邮件模板实在是件恶心事,估计搞过的同仁都有体会。 得支持多种客户端 支持响应式 疼彻心扉的 outlook 多数客户端只支持 inline 形式的 css 布局...

郁也风
今天
4
0
让哲学照亮我们的人生——读《医务工作者需要学点哲学》有感2600字

让哲学照亮我们的人生——读《医务工作者需要学点哲学》有感2600字: 作者:孙冬梅;以前读韩国前总统朴槿惠的著作《绝望锻炼了我》时,里面有一句话令我印象深刻,她说“在我最困难的时期,...

原创小博客
今天
3
0
JAVA-四元数类

public class Quaternion { private final double x0, x1, x2, x3; // 四元数构造函数 public Quaternion(double x0, double x1, double x2, double x3) { this.x0 = ......

Pulsar-V
今天
17
0
Xshell利用Xftp传输文件,使用pure-ftpd搭建ftp服务

Xftp传输文件 如果已经通过Xshell登录到服务器,此时可以使用快捷键ctrl+alt+f 打开Xftp并展示Xshell当前的目录,之后直接拖拽传输文件即可。 pure-ftpd搭建ftp服务 pure-ftpd要比vsftp简单,...

野雪球
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部