在 JavaScript 中对 utf-8 字符串使用 encodeURI() 与 escape()
Posted
技术标签:
【中文标题】在 JavaScript 中对 utf-8 字符串使用 encodeURI() 与 escape()【英文标题】:Using encodeURI() vs. escape() for utf-8 strings in JavaScript 【发布时间】:2014-09-20 02:40:15 【问题描述】:我正在处理 javascript 中的 utf-8 字符串,需要对它们进行转义。
escape() / unescape() 和 encodeURI() / decodeURI() 都可以在我的浏览器中使用。
转义()
> var hello = "안녕하세요"
> var hello_escaped = escape(hello)
> hello_escaped
"%uC548%uB155%uD558%uC138%uC694"
> var hello_unescaped = unescape(hello_escaped)
> hello_unescaped
"안녕하세요"
encodeURI()
> var hello = "안녕하세요"
> var hello_encoded = encodeURI(hello)
> hello_encoded
"%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94"
> var hello_decoded = decodeURI(hello_encoded)
> hello_decoded
"안녕하세요"
但是,Mozilla says that escape() is deprecated。
虽然 encodeURI() 和 decodeURI() 可以使用上述 utf-8 字符串,但文档(以及函数名称本身)告诉我这些方法适用于 URI;我没有看到任何地方提到的 utf-8 字符串。
简单来说,对 utf-8 字符串使用 encodeURI() 和 decodeURI() 可以吗?
【问题讨论】:
是的,这些都很好;无法正确执行 UTF 的是 escape()。也就是说,您可能想要使用 encodeURIComponent(),我认为它不仅仅是“只是”encodeURI() ***.com/questions/75980/… 和 developer.mozilla.org/en-US/docs/JavaScript/Reference/…encodeURI()
没有 UTF-8 和 escape()
有 UTF-8
【参考方案1】:
嗨!
谈到escape
和unescape
,我遵循两条规则:
-
尽可能避免使用它们。
否则,请使用它们。
尽量避免它们:
如问题中所述,escape
和 unescape
均已弃用。一般来说,应该避免使用已弃用的函数。
所以,如果 encodeURIComponent
或 encodeURI
对你有用,你应该使用它而不是 escape
。
当你无法轻易避免时使用它们:
浏览器将尽可能努力实现向后兼容。所有主流浏览器都已经实现了escape
和unescape
;他们为什么不实施它们?
如果新规范要求浏览器重新定义escape
和unescape
,它们将不得不这样做。可是等等!编写规范的人非常聪明。他们也有兴趣不破坏向后兼容性!
我意识到上述论点很弱。但请相信我,......当谈到浏览器时,不推荐使用的东西是有效的。这甚至包括已弃用的 html 标签,例如 <xmp>
和 <center>
。
使用escape
和unescape
:
很自然,下一个问题是,什么时候会使用escape
或unescape
?
最近,在处理CloudBrave 时,我不得不处理utf8
、latin1
和相互转换。
读了一堆博文后,我意识到这很简单:
var utf8_to_latin1 = function (s)
return unescape(encodeURIComponent(s));
;
var latin1_to_utf8 = function (s)
return decodeURIComponent(escape(s));
;
在不使用escape
和unescape
的情况下,这些相互转换相当复杂。通过不回避escape
和unescape
,生活会变得更简单。
希望这会有所帮助。
【讨论】:
【参考方案2】:Mozilla 表示不推荐使用 escape()。
是的,你应该避免escape()
和unescape()
简单来说,对 utf-8 字符串使用 encodeURI() 和 decodeURI() 可以吗?
是的,但根据您输入的形式和所需的输出形式,您可能需要做一些额外的工作。
根据您的问题,我假设您有一个 JavaScript 字符串,并且您想将编码转换为 UTF-8,最后以某种转义形式存储该字符串。
首先需要注意的是,JavaScript 字符串编码是 UCS-2,类似于 UTF-16,不同于 UTF-8。
见:https://mathiasbynens.be/notes/javascript-encoding
encodeURIComponent()
非常适合这项工作,因为它将 UCS-2 JavaScript 字符串转换为 UTF-8 并以 %nn
子字符串序列的形式对其进行转义,其中每个 nn
是每个字节的两个十六进制数字。
但是encodeURIComponent()
不会转义 ASCII 范围内的字母、数字和少数其他字符。但这很容易解决。
例如,如果你想将一个 JavaScript 字符串转换为一个数字数组,代表原始字符串 UTF-8 编码的字节,你可以使用这个函数:
//
// Convert JavaScript UCS2 string to array of bytes representing the string UTF8 encoded
//
function StringUTF8AsBytesArrayFromString( s )
var i,
n,
u;
u = [];
s = encodeURIComponent( s );
n = s.length;
for( i = 0; i < n; i++ )
if( s.charAt( i ) == '%' )
u.push( parseInt( s.substring( i + 1, i + 3 ), 16 ) );
i += 2;
else
u.push( s.charCodeAt( i ) );
return u;
如果要将字符串转换为十六进制表示:
//
// Convert JavaScript UCS2 string to hex string representing the bytes of the string UTF8 encoded
//
function StringUTF8AsHexFromString( s )
var u,
i,
n,
s;
u = StringUTF8AsBytesArrayFromString( s );
n = u.length;
s = '';
for( i = 0; i < n; i++ )
s += ( u[ i ] < 16 ? '0' : '' ) + u[ i ].toString( 16 );
return s;
如果将for循环中的行改为
s += '%' + ( u[ i ] < 16 ? '0' : '' ) + u[ i ].toString( 16 );
(在每个十六进制数字前添加%
符号)
生成的转义字符串(UTF-8 编码)可以用decodeURIComponent()
转回 JavaScript UCS-2 字符串
【讨论】:
参见 String.prototype.codePointAt() 和 String.fromCharCode() 了解 utf-8 兼容的单字符转换。 更正 - String.fromCodePoint(); 我想提供一个解决方案,它既适用于旧版浏览器(whereString.fromCodePoint 不可用),也适用于当前浏览器和未来可能会放弃转义/取消转义的浏览器【参考方案3】:永远可以使用encodeURI()
或encodeURIComponent()
。让我们试试吧:
console.log(encodeURIComponent('@#*'));
输入:@#*
。输出:%40%23*
。等等,*
字符到底发生了什么?为什么没有转换?想象一下:你问用户要删除什么文件,他们的回答是*
。在服务器端,您使用encodeURIComponent()
转换它,然后运行rm *
。好吧,有消息告诉你:using encodeURIComponent()
means you just deleted all files.
使用fixedEncodeURI()
,尝试编码完整的 URL(即所有example.com?arg=val
),如MDN encodeURI() Documentation 中定义和进一步解释...
function fixedEncodeURI(str) return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']');
或者,您可能需要使用fixedEncodeURIComponent()
,在尝试对 URL 的一部分进行编码时(即arg
或example.com?arg=val
中的val
),如@987654325 中的定义和进一步解释@...
function fixedEncodeURIComponent(str) return encodeURIComponent(str).replace(/[!'()*]/g, function(c) return '%' + c.charCodeAt(0).toString(16); );
如果您无法根据以上描述区分它们,我总是喜欢将其简化为:
fixedEncodeURI()
:不会将 +@?=:#;,$&
编码为它们的 http 编码等效项(因为 &
和 +
是常见的 URL 运算符)
fixedEncodeURIComponent()
将将 +@?=:#;,$&
编码为它们的 http 编码等效项。
【讨论】:
以上是关于在 JavaScript 中对 utf-8 字符串使用 encodeURI() 与 escape()的主要内容,如果未能解决你的问题,请参考以下文章