在 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】:

嗨!

谈到escapeunescape,我遵循两条规则:

    尽可能避免使用它们。 否则,请使用它们。

尽量避免它们:

如问题中所述,escapeunescape 均已弃用。一般来说,应该避免使用已弃用的函数。

所以,如果 encodeURIComponentencodeURI 对你有用,你应该使用它而不是 escape

当你无法轻易避免时使用它们:

浏览器将尽可能努力实现向后兼容。所有主流浏览器都已经实现了escapeunescape;他们为什么不实施它们?

如果新规范要求浏览器重新定义escapeunescape,它们将不得不这样做。可是等等!编写规范的人非常聪明。他们也有兴趣不破坏向后兼容性!

我意识到上述论点很弱。但请相信我,......当谈到浏览器时,不推荐使用的东西是有效的。这甚至包括已弃用的 html 标签,例如 <xmp><center>

使用escapeunescape

很自然,下一个问题是,什么时候会使用escapeunescape

最近,在处理CloudBrave 时,我不得不处理utf8latin1 和相互转换。

读了一堆博文后,我意识到这很简单:

var utf8_to_latin1 = function (s) 
    return unescape(encodeURIComponent(s));
;
var latin1_to_utf8 = function (s) 
    return decodeURIComponent(escape(s));
;

在不使用escapeunescape 的情况下,这些相互转换相当复杂。通过不回避escapeunescape,生活会变得更简单。

希望这会有所帮助。

【讨论】:

【参考方案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 ] &lt; 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 的一部分进行编码时(即argexample.com?arg=val 中的val),如@987654325 中的定义和进一步解释@...

function fixedEncodeURIComponent(str) 
 return encodeURIComponent(str).replace(/[!'()*]/g, function(c) 
   return '%' + c.charCodeAt(0).toString(16);
 );

如果您无法根据以上描述区分它们,我总是喜欢将其简化为:

fixedEncodeURI()不会+@?=:#;,$&amp; 编码为它们的 http 编码等效项(因为 &amp;+ 是常见的 URL 运算符) fixedEncodeURIComponent() +@?=:#;,$&amp; 编码为它们的 http 编码等效项。

【讨论】:

以上是关于在 JavaScript 中对 utf-8 字符串使用 encodeURI() 与 escape()的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JavaScript 中对字符串进行排序

如何在javascript中对字符串进行数字排序

在javascript和html中对单引号进行操作[重复]

为啥需要方括号来在 Javascript 中对 Map 的所有元素进行字符串化?

JavaScript中对数组的操作

如何在 JavaScript 中对文本框进行验证 [关闭]