JavaScript:转义符后不要匹配

3

我正在使用正则表达式来替换变量中的子字符串$0。但是现在我正在寻找一种表达式,当$0被转义成\$0时不匹配。

代码示例如下:

let string = "Hello '$0'. '$0' becomes the World. This shall remain \$0";
string = string.replace(/.../g, "World");
// "Hello 'World'. 'World' becomes World. This shall remain \$0"

什么是处理上述示例代码中的情况的适当表达方式?
非常感谢您的提前帮助!

请解释一下你正在做什么,提供一段带有正则表达式的当前代码将会很有帮助。 - Wiktor Stribiżew
谢谢您的回复。我已经添加了一个代码示例来进一步说明问题。 - Daniel Messner
你需要考虑转义实体吗?比如说,对于 \\\\$0 \\\$0 应该期望什么输出? - Wiktor Stribiżew
你需要在字符串字面量中使用 "… \\$0"。单个反斜杠不起作用,它只会产生与 "… $0" 相同的字符串。 - Bergi
4个回答

1

正确的方法是在 $0 之前考虑任何转义的反斜杠:\\$0 \$0 应该变成 \\World \$0,因为第一个 \\ 表示一个反斜杠,紧接着的 $0 是未转义的。

因此,您可以使用

.replace(/((?:^|[^\\])(?:\\{2})*)\$0/g, "$1World")

请查看正则表达式演示

请注意,即使World以数字开头,在JavaScript中也应该能正常工作。您可以对模式添加更多限制,例如在\$0之后添加单词边界或(?!\d)前瞻,以确保紧接其后没有数字,但这不在问题范围内。

模式细节

  • ((?:^|[^\\])(?:\\{2})*) - 捕获组1:
    • (?:^|[^\\]) - 字符串起始位置或除\外的字符
    • (?:\\{2})* - 双反斜杠的0个或多个重复
  • \$0 - $0子字符串。

JS演示:

var s = "Hello '$0'. '$0' becomes the World. This shall remain \\$0. Extra: \\\\$0 is World, \\$0 is escaped.";
console.log("The string is: '" + s + "'");
console.log("The result is: '" + s.replace(/((?:^|[^\\])(?:\\{2})*)\$0/g, "$1World") + "'");

注意:字符串文字包含两个反斜杠,其中字符串包含一个字面上的反斜杠。如果使用单个反斜杠,则会消失(当转义序列未知时),或者形成字符串转义序列(例如\n表示换行符,\t将定义制表符等)。


0
通常情况下,您会在这种情况下使用负回顾后断言,但由于它在您的情况下无法使用,因此您可以尝试像这样绕过它:
([^ \\])\$0([^ \\])

enter image description here

正则表达式演示 - 在右上角您可以看到单个正则表达式组件的描述。

这背后的思想是将'$0'分成三个部分-' + $0 + '。开放和关闭括号在它们自己的组中-这允许您提取前面和后面的符号,$0要替换(很快您将看到为什么这很重要)。我们不匹配在$0之前有\或空格的情况。这使我们能够捕获整个$0以及周围的符号,无论它们是什么(例如'', "", [], ())。

在您的代码中,您用包围原始$0的符号替换$0为单词World - 这是可能的,因为我们最初将它们作为组捕获。因此,您的代码将是:

let string = "Hello '$0'. '$0' becomes the World. This shall remain \$0";
string = string.replace(/([^ \\])\$0([^ \\])/g, "$1World$2");

奖励:一些示例结果:

'' -> Hello 'World'. 'World' becomes the World. This shall remain $0
"" -> Hello "World". "World" becomes the World. This shall remain $0
[] -> Hello [World]. [World] becomes the World. This shall remain $0

漂亮的图片,它们代表什么? - user557597

-1

理想情况下是使用负回顾后发:

/(?<!\\)\$0/g

很遗憾,这在所有主流浏览器中都不被支持(如果有的话)。 您还可以仅在$0之前的字符不是\时进行捕获。

/(?<!\\)\$0/g

但这也会捕获(并替换)$0前面的字符。
我想不到使用正则表达式实现这一点的方法,因此建议循环遍历字符串并比较字符(提示:从后面开始)。


-1
在这种情况下,使用负回顾后断言

let string = "Hello '$0'. '$0' becomes the World. This shall remain \$0";
string = string.replace(/(?<!\\)\$0/g, "World");
// "Hello 'World'. 'World' becomes World. This shall remain \$0"

负回顾后断言在大多数浏览器中不起作用,但在ECMAScript 2018中被接受。现在它已经在V8引擎中实现,因此应该可以在Chrome 62和Node.js中使用。有关更多详细信息,请查看this answer

如果您想支持例如Edge或Firefox,您可以使用参考替换字符串:

let string = "Hello '$0'. '$0' becomes the World. This shall remain \$0";
string = string.replace(/([^\\]|^)\$0/g, "$1World");
// "Hello 'World'. 'World' becomes World. This shall remain \$0"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接