4

为此答案运行一些测试时,我注意到以下意外行为。这将删除第一个之后的所有出现<tag>

var input = "<text><text>extra<words><text><words><something>";
Regex.Replace(input, @"(<[^>]+>)(?<=\1.*\1)", "");
// <text>extra<words><something>

但这不会:

Regex.Replace(input, @"(?<=\1.*)(<[^>]+>)", "");
// <text><text>extra<words><text><words><something>

同样,这将删除<tag>最后一个之前的所有出现:

Regex.Replace(input, @"(<[^>]+>)(?=.*\1)", "");
// extra<text><words><something>

但这不会:

Regex.Replace(input, @"(?=\1.*\1)(<[^>]+>)", "");
// <text><text>extra<words><text><words><something>

所以这让我想到……

在 .NET 正则表达式引擎中,反向引用是否需要出现它所引用的组之后?或者这些模式是否有其他原因导致它们不起作用?

4

1 回答 1

4

你的问题也让我思考,所以我用RegexBuddy进行了一些测试,令我惊讶的是,你说的第二个正则表达式(?<=\1.*)(<[^>]+>)不起作用,而其他的正则表达式完全像你说的那样工作。然后我在 C# 代码中尝试了相同的表达式- 第二个 -但它不像你发生的那样工作。

这让我感到困惑,然后我注意到我的 RegexBuddy 版本可以追溯到 2008 年,因此 .NET 引擎的工作方式肯定发生了一些变化,但这揭示了一个我认为是合理的事实,似乎在 2008 年之前回顾在表达式的其余部分匹配后进行评估。我觉得这种行为对于lookbehinds来说有点可接受,因为你需要先匹配一些东西,然后再往后看才能匹配它之前的东西。

尽管如此,这些天的引擎似乎在遇到它们时会评估环视,我能够通过使用以下表达式找到这一点,这就像你的情况的相反情况:

(?<=(\w))\1

如您所见,我在正则表达式中捕获了一个单词字符并在其外部引用了它。我在字符串上对此进行了测试hello,它与预期的第二个l字符匹配,这证明在尝试匹配表达式的其余部分之前执行了lookbehind。

结论:是的,反向引用需要出现在它引用的组之后,否则它将没有匹配语义。

于 2013-08-20T23:09:28.560 回答