105

我不确定这叫什么,所以我很难找到它。如何使用 JavaScript解码带有 unicodehttp\u00253A\u00252F\u00252Fexample.com的字符串?http://example.com我试过unescape, decodeURIdecodeURIComponent所以我想唯一剩下的就是字符串替换了。

编辑:字符串不是输入的,而是来自另一段代码的子字符串。所以要解决这个问题,你必须从这样的事情开始:

var s = 'http\\u00253A\\u00252F\\u00252Fexample.com';

我希望这能说明为什么 unescape() 不起作用。

4

7 回答 7

132

编辑(2017-10-12)

@MechaLynx 和 @Kevin-Weber 注意,unescape()非浏览器环境已弃用,TypeScript 中不存在。decodeURIComponent是一个插入式替代品。为了更广泛的兼容性,请改用以下内容:

decodeURIComponent(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'

原答案:

unescape(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'

您可以将所有工作卸载到JSON.parse

于 2012-10-13T04:24:51.473 回答
124

更新:请注意,这是一个适用于旧版浏览器或非浏览器平台的解决方案,并且出于教学目的而保持活动状态。请参阅下面@radicand 的答案以获取更多最新答案。


这是一个 unicode 转义字符串。首先字符串被转义,然后用 unicode 编码。要恢复正常:

var x = "http\\u00253A\\u00252F\\u00252Fexample.com";
var r = /\\u([\d\w]{4})/gi;
x = x.replace(r, function (match, grp) {
    return String.fromCharCode(parseInt(grp, 16)); } );
console.log(x);  // http%3A%2F%2Fexample.com
x = unescape(x);
console.log(x);  // http://example.com

解释一下:我使用正则表达式来查找\u0025. 但是,由于我的替换操作只需要这个字符串的一部分,所以我使用括号来隔离我要重用的部分,0025. 这个孤立的部分称为一个组。

表达式末尾的gi部分表示它应该匹配字符串中的所有实例,而不仅仅是第一个,并且匹配应该不区分大小写。鉴于示例,这可能看起来没有必要,但它增加了多功能性。

现在,要从一个字符串转换为下一个字符串,我需要对每个匹配的每一组执行一些步骤,而我不能通过简单地转换字符串来做到这一点。有用的是,String.replace 操作可以接受一个函数,该函数将为每个匹配项执行。该函数的返回将替换字符串中的匹配项本身。

我使用此函数接受的第二个参数,即我需要使用的组,并将其转换为等效的 utf-8 序列,然后使用内置unescape函数将字符串解码为正确的形式。

于 2011-10-25T06:36:05.033 回答
21

请注意,例如,unescape()推荐使用,并且不适用于 TypeScript 编译器。

根据 radicand 的回答和下面的评论部分,这是一个更新的解决方案:

var string = "http\\u00253A\\u00252F\\u00252Fexample.com";
decodeURIComponent(JSON.parse('"' + string.replace(/\"/g, '\\"') + '"'));

http://example.com

于 2016-11-03T20:33:22.017 回答
6

使用JSON.decode它会带来一些您必须注意的重大缺点:

  • 您必须将字符串用双引号引起来
  • 许多字符不受支持,必须自行转义。例如,将以下任何内容传递给JSON.decode(将它们用双引号括起来之后)都会出错,即使这些都是有效的:\\n, \n, \\0,a"a
  • 它不支持十六进制转义:\\x45
  • 它不支持 Unicode 代码点序列:\\u{045}

还有其他警告。从本质上讲,JSON.decode用于此目的是一种 hack,并不像您可能一直期望的那样工作。您应该坚持使用该JSON库来处理 JSON,而不是字符串操作。


我最近自己遇到了这个问题,想要一个强大的解码器,所以我自己写了一个。它是完整且经过彻底测试的,可在此处获得:https ://github.com/iansan5653/unraw 。它尽可能地模仿 JavaScript 标准。

解释:

源代码大约有 250 行,所以我不会在这里全部包含在内,但本质上它使用以下正则表达式来查找所有转义序列,然后解析它们parseInt(string, 16)以解码 base-16 数字,然后String.fromCodePoint(number)获取相应的字符:

/\\(?:(\\)|x([\s\S]{0,2})|u(\{[^}]*\}?)|u([\s\S]{4})\\u([^{][\s\S]{0,3})|u([\s\S]{0,4})|([0-3]?[0-7]{1,2})|([\s\S])|$)/g

评论(注意:这个正则表达式匹配所有转义序列,包括无效的。如果字符串会在 JS 中引发错误,它会在我的库中引发错误[即,'\x!!'将出错]):

/
\\ # All escape sequences start with a backslash
(?: # Starts a group of 'or' statements
(\\) # If a second backslash is encountered, stop there (it's an escaped slash)
| # or
x([\s\S]{0,2}) # Match valid hexadecimal sequences
| # or
u(\{[^}]*\}?) # Match valid code point sequences
| # or
u([\s\S]{4})\\u([^{][\s\S]{0,3}) # Match surrogate code points which get parsed together
| # or
u([\s\S]{0,4}) # Match non-surrogate Unicode sequences
| # or
([0-3]?[0-7]{1,2}) # Match deprecated octal sequences
| # or
([\s\S]) # Match anything else ('.' doesn't match newlines)
| # or
$ # Match the end of the string
) # End the group of 'or' statements
/g # Match as many instances as there are

例子

使用该库:

import unraw from "unraw";

let step1 = unraw('http\\u00253A\\u00252F\\u00252Fexample.com');
// yields "http%3A%2F%2Fexample.com"
// Then you can use decodeURIComponent to further decode it:
let step2 = decodeURIComponent(step1);
// yields http://example.com
于 2019-08-19T16:25:55.797 回答
2

我没有足够的代表将其置于对现有答案的评论之下:

unescape仅在使用 URI(或任何编码的 utf-8)时不推荐使用,这可能是大多数人需要的情况。encodeURIComponent将 js 字符串转换为转义的 UTF-8,并且decodeURIComponent仅适用于转义的 UTF-8 字节。它会引发错误,decodeURIComponent('%a9'); // error因为扩展的 ascii 不是有效的 utf-8(即使它仍然是一个 unicode 值),而unescape('%a9'); // ©因此在使用 decodeURIComponent 时您需要知道您的数据。

decodeURIComponent 不会在"%C2"任何单独的字节上工作,0x7f因为在 utf-8 中表示代理的一部分。但是decodeURIComponent("%C2%A9") //gives you ©Unescape 不能正常工作并且// ©它不会抛出错误,所以如果你不知道你的数据, unescape 可能会导致错误的代码。

于 2018-03-15T22:15:59.913 回答
0

就我而言,我试图unescape像 HTML 文件一样

"\u003Cdiv id=\u0022app\u0022\u003E\r\n    \u003Cdiv data-v-269b6c0d\u003E\r\n        \u003Cdiv data-v-269b6c0d class=\u0022menu\u0022\u003E\r\n    \u003Cdiv data-v-269b6c0d class=\u0022faux_column\u0022\u003E\r\n        \u003Cdiv data-v-269b6c0d class=\u0022row\u0022\u003E\r\n            \u003Cdiv data-v-269b6c0d class=\u0022col-md-12\u0022\u003E\r\n"  

<div id="app">
    <div data-v-269b6c0d>
        <div data-v-269b6c0d class="menu">
    <div data-v-269b6c0d class="faux_column">
        <div data-v-269b6c0d class="row">
            <div data-v-269b6c0d class="col-md-12">

以下适用于我的情况:

const jsEscape = (str: string) => {
  return str.replace(new RegExp("'", 'g'),"\\'");
}

export const decodeUnicodeEntities = (data: any) => {
  return unescape(jsEscape(data));
}

// Use it
const data = ".....";
const unescaped = decodeUnicodeEntities(data); // Unescaped html

于 2021-07-13T09:05:42.960 回答
0

这不是这个确切问题的答案,但是对于那些通过搜索结果访问此页面并且试图(像我一样)在给定一系列转义代码点的情况下构造单个 Unicode 字符的人,请注意,您可以传递多个String.fromCodePoint()喜欢这样的论点:

String.fromCodePoint(parseInt("1F469", 16), parseInt("200D", 16), parseInt("1F4BC", 16)) // ‍

您当然可以解析您的字符串以提取十六进制代码点字符串,然后执行以下操作:

let codePoints = hexCodePointStrings.map(s => parseInt(s, 16));
let str = String.fromCodePoint(...codePoints);
于 2021-08-20T19:33:31.790 回答