为啥正则表达式构造函数需要双重转义?

Posted

技术标签:

【中文标题】为啥正则表达式构造函数需要双重转义?【英文标题】:Why do regex constructors need to be double escaped?为什么正则表达式构造函数需要双重转义? 【发布时间】:2022-01-15 17:21:57 【问题描述】:

在下面的正则表达式中,\s 表示一个空格字符。我想正则表达式解析器正在遍历字符串并看到 \ 并知道下一个字符是特殊的。

但情况并非如此,因为需要双重转义。

这是为什么?

var res = new RegExp('(\\s|^)' + foo).test(moo);

是否有一个具体的例子说明单个转义如何被误解为其他内容?

【问题讨论】:

记住,需要澄清的不是 Java 或 Regexp 构造函数,而是编译器(或解析器)。 补充已经正确的答案:请注意,如果您在 javascript 中编写 RegExp 文字,您 不需要 需要转义反斜杠,因为您会怀疑: /(\s|^)/ 相关:***.com/a/37329801/1225328. 【参考方案1】:

您正在通过将字符串传递给 RegExp 构造函数来构造正则表达式。

\ 是字符串文字中的转义字符。

\ 被字符串文字解析所消耗……

const foo = "foo";
const string = '(\s|^)' + foo;
console.log(string);

...所以您传递给 RegEx 编译器的数据是纯 s 而不是 \s

您需要转义\ 以将\ 表达为数据,而不是转义字符本身。

【讨论】:

这既适用于常规字符串文字,也适用于模板字符串文字。【参考方案2】:

在您创建字符串的代码中,反斜杠首先是一个 javascript 转义字符,这意味着像 \t\n\" 等转义序列将被翻译成对应的 javascript (制表符、换行符、引号等),这将成为字符串的一部分。双反斜杠表示实际字符串本身中的单个反斜杠,因此如果您想要字符串中的反斜杠,请先将其转义。

因此,当您通过说var someString = '(\\s|^)' 生成字符串时,您真正要做的是创建一个值为(\s|^) 的实际字符串。

【讨论】:

【参考方案3】:

正则表达式需要\s 的字符串表示,在JavaScript 中可以使用文字"\\s" 生成。

这里有一个活生生的例子来说明为什么"\s" 是不够的:

alert("One backslash:          \s\nDouble backslashes: \\s");

注意\s 之前的额外\ 如何更改输出。

【讨论】:

【参考方案4】:

\ 在字符串中用于转义特殊字符。如果您想在字符串中使用反斜杠(例如,对于 \s 中的 \),您必须通过反斜杠对其进行转义。所以 \ 变成 \\ 。

编辑:甚至不得不在这里做,因为 \\ 在我的回答中变成了 \。

【讨论】:

【参考方案5】:

如前所述,在字符串文字中,反斜杠表示转义序列,而不是文字反斜杠字符,但 RegExp 构造函数通常需要传递给它的字符串中的文字反斜杠字符,因此代码应该有 @987654321 @s 代表文字反斜杠,在大多数情况下

一个问题是双重转义元字符很乏味。有一种方法可以将字符串传递给new RegExp 而无需双重转义:使用String.raw 模板标签,这是 ES6 的一项功能,它允许您编写一个将由解释器逐字解析的字符串 verbatim,没有任何转义序列的解析。例如:

console.log('\\'.length);           // length 1: an escaped backslash
console.log(`\\`.length);           // length 1: an escaped backslash
console.log(String.raw`\\`.length); // length 2: no escaping in String.raw!

因此,如果您希望保持代码可读性,并且您有许多反斜杠,则可以使用 String.raw 仅键入 一个 反斜杠,当模式需要反斜杠时:

const sentence = 'foo bar baz';
const regex = new RegExp(String.raw`\bfoo\sbar\sbaz\b`);
console.log(regex.test(sentence));

但有更好的选择。一般来说,没有太多理由使用new RegExp,除非您需要从现有变量动态创建正则表达式。否则,您应该改用正则表达式文字,它不需要对元字符进行双重转义,也不需要写出String.raw 以保持模式可读:

const sentence = 'foo bar baz';
const regex = /\bfoo\sbar\sbaz\b/;
console.log(regex.test(sentence));

最好只在必须动态创建模式时才使用new RegExp,如以下sn-p:

const sentence = 'foo bar baz';
const wordToFind = 'foo'; // from user input

const regex = new RegExp(String.raw`\b$wordToFind\b`);
console.log(regex.test(sentence));

【讨论】:

以上是关于为啥正则表达式构造函数需要双重转义?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式

正则表达式

正则表达式

正则表达式

用正则表达式不就可以让用户名不能包含一些字符了吗,为啥还要转义

JS常用正则表达&RegExp对象