如何在 JavaScript 中获取原始字符串并将所有转义序列转换为各自的字符?换句话说,反之String.raw
。例如:
unraw("\\x61\\x62\\x63 \\u{1F4A9} \\u0041");
// => "abc A";
我试过JSON.parse
了,但它只支持最后一种格式(\\u0041
)。也不unescape
是decodeURI
我要找的东西。
如何在 JavaScript 中获取原始字符串并将所有转义序列转换为各自的字符?换句话说,反之String.raw
。例如:
unraw("\\x61\\x62\\x63 \\u{1F4A9} \\u0041");
// => "abc A";
我试过JSON.parse
了,但它只支持最后一种格式(\\u0041
)。也不unescape
是decodeURI
我要找的东西。
我认为你基本上有三个选择:
new Function
(或什eval
至)来执行它,这意味着您可以执行任意代码;或者#1有点痛苦,但真的没那么糟糕,没有那么多需要处理。#2 存在所有关于信任字符串内容不是恶意代码的常见问题,因为使用eval
或调用函数new Function
创建允许任意代码执行。#3 是一个相当繁重的解决方案。
仔细观察#1,EscapeSequence分解为:
\
后跟'"\bfnrtv
.\xHH
在哪里H
\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));
我敢肯定,这可以清理一下。
看起来那里什么都没有,我已经写了自己的,这比@TJ Crowder 的出色答案更强大。值得注意的是,我想要一个行为与 JS 解析器处理字符串几乎完全相同的函数,这意味着它需要在无效代码上出错。此函数还可以正确处理双转义序列"\\\x61"
,例如应该 yield"\\x61"
和 Unicode 代理,以及可选地正确处理八进制文字或至少在遇到它们时抛出错误。最后,它支持转义不需要转义的字符,例如"\R"
.
我还没有机会彻底测试它,但我已经在这里上传了它https://github.com/iansan5653/unraw并且最终将编写大量的单元测试并将其作为 NPM 模块发布。