正则表达式中的 Regex.Replace 忽略非捕获组

4
我有以下代码:
var pattern = @"(?:red).*(\d+)";
var regX = new Regex(pattern);
var input = "this is red with number 111";
var replaced = regX.Replace(input, "666");

替换后的结果是:this is 666,而不是:this is red with number 666 为什么会发生这种情况?

1
使用类似 http://regex101.com 的工具来帮助调试正则表达式。 - DLeh
2
当你想创建一个特定于.NET的正则表达式时,请不要使用regex101.com,因为该网站不支持.NET版本。请使用http://regexhero.com,在那里您可以测试正则表达式的性能,并且http://regexstorm.net非常有帮助,因为您可以快速地创建永久链接,这些链接永不过期,因为所有参数都通过GET查询字符串传递。 - Wiktor Stribiżew
@stribizhev - 非常有用。谢谢。 - MaYaN
2个回答

11

你需要使用基于正向回顾断言的正则表达式,因为你的正则表达式中的 (?:red).* 部分匹配了字符。因此在替换时,所有匹配到的字符都被替换了。

var pattern = @"(?<=red.*?)\d+";
var regX = new Regex(pattern);
var input = "this is red with number 111";
var replaced = regX.Replace(input, "666");

或者

使用捕获组。

var pattern = @"(red.*?)\d+";

$1\1 + 666替换匹配的字符


该死,正则表达式大师。我几乎在所有的正则表达式问题中都能看到你。你是怎么学会这么好的正则表达式的?每次我尝试开始学习它时,我总是失败。 - Soner Gönül
var replaced = regX.Replace(input, "$1" + "666"); - Avinash Raj
1
@Avinash,第二个给出的是:“这是1666美元”。 - MaYaN
1
这个正则表达式也会在你有一个像 It occurred at least 23 times. 这样的字符串时触发,因为在 red 前面没有单词边界。 - Wiktor Stribiżew
1
@MaYaN regX.Replace(input, "${1}666") 替换完成。 - Taemyr
显示剩余5条评论

2
你的正则表达式未能按预期工作,因为它匹配了数字111之前的红色文本。如果你不想匹配数字之前的文本,可以使用.NET正则表达式中非常好用的变量后顾(variable look-behind):
(?<=\bred.*)\d+

代码:

var pattern = @"(?<=\bred.*)\d+";
var regX = new Regex(pattern);
var input = "this is red with number 111";
var replaced = regX.Replace(input,"666");

输出:

enter image description here

请参见演示(上下文选项卡)

编辑:

如果您想使用捕获组替换,可以使用以下代码:

var rx = new Regex(@"(\bred.*?)\d+");
var result = rx.Replace("this is red with number 111", "${1}666");

替换字符串中的大括号${1}将确保引擎将其解释为组号,而不是替换数字的一部分。

在我的回答中,我使用RegexStorm网站进行演示。我希望你也会觉得它有用。 - Wiktor Stribiżew

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