【问题标题】:Do backreferences need to come after the group they reference?反向引用是否需要在他们引用的组之后?
【发布时间】:2013-08-23 00:49:41
【问题描述】:

在为this answer 运行一些测试时,我注意到以下意外行为。这将删除第一个之后出现的所有<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>

同样,这将删除最后一个之前出现的所有&lt;tag&gt;

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

但这不会:

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

所以这让我开始思考……

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

【问题讨论】:

  • 从逻辑上讲,您需要先捕获某些内容,然后将其用作反向引用,否则递归正则表达式 like this one 将失败 :) PS:不仅在 .net 中,我认为在所有情况下都是如此口味。在php pcre中查看演示
  • @HamZa 谢谢,这是一个很好的观点。我会认为环视断言 可能 会有所不同,因为(据我所知)它们必须在字符串的匹配部分之后进行评估。换句话说,它必须先找到&lt;tag&gt;,然后才能检查断言——但我对正则表达式的内部了解不多,所以我可能错了。另外,我想在大多数情况下,如果引擎的行为取决于评估它的顺序而不是它在模式中出现的顺序,那将会令人惊讶。

标签: c# .net regex backreference


【解决方案1】:

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

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

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

(?<=(\w))\1

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

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

【讨论】:

  • 错误消息告诉您(?&lt;=\1)\w 是无效语法,因为它包含对不存在的捕获组的引用。 (?&lt;=\1)(\w) 是有效的语法,但它永远不会成功,因为它会在该组参与匹配之前尝试匹配该组的内容。
  • @AlanMoore 你当然是正确的,错误更正了。谢谢。
  • 感谢您抽出宝贵时间回复。实际上,如果它出现在组之前,我也不例外;它只是不匹配任何东西。我曾考虑过,如果它引用的组尚未被捕获,则反向引用可能匹配一个空字符串,但显然它根本不匹配任何东西,例如Regex.Matches("hello", @"\1()") 不匹配任何内容,但 Regex.Matches("hello", @"(?!\1)()") 匹配每个字符周围的 0 长度字符串。
  • @p.s.w.g 我很抱歉异常声明,艾伦在他的评论中提到了这一点,但我一定忘记修复结论部分。如果它引用的组尚未匹配,则反向引用不匹配任何内容是正确的。然而,关于参数的要点是环视是在表达式的其余部分之后还是之前匹配,可以肯定地说它是在立即遇到时匹配的。
猜你喜欢
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多