2

如何在 JavaScript 中获取原始字符串并将所有转义序列转换为各自的字符?换句话说,反之String.raw。例如:

unraw("\\x61\\x62\\x63 \\u{1F4A9} \\u0041");
// => "abc  A";

我试过JSON.parse了,但它只支持最后一种格式(\\u0041)。也不unescapedecodeURI我要找的东西。

4

2 回答 2

1

我认为你基本上有三个选择:

  1. 编写自己的函数来处理 JavaScript 允许在字符串中使用的各种类型的转义;或者
  2. 利用运行此代码的 JavaScript 引擎中内置的 JavaScript 解析器,这意味着信任字符串的内容,因为您必须使用new Function(或什eval至)来执行它,这意味着您可以执行任意代码;或者
  3. 使用像Esprima或类似的解析器

#1有点痛苦,但真的没那么糟糕,没有那么多需要处理。#2 存在所有关于信任字符串内容不是恶意代码的常见问题,因为使用eval或调用函数new Function创建允许任意代码执行。#3 是一个相当繁重的解决方案。

仔细观察#1,EscapeSequence分解为:

  • 单个字符转义,\后跟'"\bfnrtv.
  • 十六进制转义,十六进制数字\xHH在哪里H
  • Unicode 转义,\uHHHH或者\u{H+)再次H是十六进制数字

这实际上并不是那么糟糕。这是一个快速和肮脏的:

// Note: This does not implement LegacyOctalEscapeSequence (https://tc39.es/ecma262/#prod-annexB-LegacyOctalEscapeSequence)
function unraw(str) {
    return str.replace(/\\[0-9]|\\['"\bfnrtv]|\\x[0-9a-f]{2}|\\u[0-9a-f]{4}|\\u\{[0-9a-f]+\}|\\./ig, match => {
        switch (match[1]) {
            case "'":
            case "\"":
            case "\\":
                return match[1];
            case "b":
                return "\b";
            case "f":
                return "\f";
            case "n":
                return "\n";
            case "r":
                return "\r";
            case "t":
                return "\t";
            case "v":
                return "\v";
            case "u":
                if (match[2] === "{") {
                    return String.fromCodePoint(parseInt(match.substring(3), 16));
                }
                return String.fromCharCode(parseInt(match.substring(2), 16));
            case "x":
                return String.fromCharCode(parseInt(match.substring(2), 16));
            case "0":
                return "\0";
            default: // E.g., "\q" === "q"
                return match.substring(1);
        }
    });
}
console.log(String.raw`${unraw("\\x61\\x62\\x63 \\u{1F4A9} \\u0041")}`);
// Double-check result
const str =           "\x61\x62\x63 \u{1F4A9} \u0041";
const raw = String.raw`\x61\x62\x63 \u{1F4A9} \u0041`;
console.log(str === unraw(raw));

我敢肯定,这可以清理一下。

于 2019-08-02T16:28:59.650 回答
-1

看起来那里什么都没有,我已经写了自己的,这比@TJ Crowder 的出色答案更强大。值得注意的是,我想要一个行为与 JS 解析器处理字符串几乎完全相同的函数,这意味着它需要在无效代码上出错。此函数还可以正确处理双转义序列"\\\x61",例如应该 yield"\\x61"和 Unicode 代理,以及可选地正确处理八进制文字或至少在遇到它们时抛出错误。最后,它支持转义不需要转义的字符,例如"\R".

我还没有机会彻底测试它,但我已经在这里上传了它https://github.com/iansan5653/unraw并且最终将编写大量的单元测试并将其作为 NPM 模块发布。

于 2019-08-02T19:17:48.117 回答