【问题标题】:why the name capture group does not capture the same value?为什么名称捕获组不捕获相同的值?
【发布时间】:2019-07-24 09:33:32
【问题描述】:
^(?'a'1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.(?&a)$

我正在学习正则表达式,但遇到了无法捕获的问题 255.255255.25

我的正则表达式有什么问题?

如果我重复使用相同的模式,它会起作用

^(?:1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.(?:1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$

但是当我尝试使用名称捕获组(?&a)时它不起作用

【问题讨论】:

  • 您使用什么语言/工具?
  • 它是一个 PCRE(php) 正则表达式
  • 你如何测试它?它适用于 perl 和 Notepad++。但它不适用于 php 或 regex101。
  • 我在 regex101 上测试它

标签: php regex pcre


【解决方案1】:

这取决于 PCRE 版本。来自PCRE news10.30:

新的实现允许回溯到递归组调用 在模式中,使其与 Perl 更兼容,并且还修复了一些 其他以前难以解决的问题。

  • 在 PCRE v10.30 之前:最初,递归组调用默认是原子的。

    你的交替顺序是陷阱,因为第一个成功的选择获胜。在您的情况下,1?[0-9]?[0-9] 匹配 25(从未测试过其他替代方案),然后当正则表达式引擎尝试 $ 并失败时,组中无法进行回溯。 您可以像这样解决编写命名捕获的问题:

    (?<a>1[0-9]{0,2}|[3-9][0-9]?|2(?:[0-4][0-9]?|5[0-5]?|[6-9])?|0)
    

    有点长,但每个数字都遵循一条独特的成功之路:demo

  • 自 PCRE 10.30 以来:在较新的 PCRE 版本中,递归组调用不再是原子的(回溯是可能的,如在 Perl 中)并且您的模式可以正常工作:https://3v4l.org/HUICY

请注意,实际上,regex101 和 PHP

【讨论】:

    【解决方案2】:

    奇怪的是,子例程似乎是原子检查的。 基本上,255. 部分正常匹配(尽管您应该将. 替换为\. 以显式捕获一个点而不是任何字符),但将255a 组匹配第一个匹配25可能性(1?[0-9]?[0-9]),但$ 失败,它回溯整个子例程,而不是尝试其他可能性。 一个解决方案是重新安排您将25[0-5] 放在首位的可能性。

    模式

    ^(?'a'25[0-5]|1?[0-9]?[0-9]|2[0-4][0-9])\.(?&a)$
    

    为我工作。

    【讨论】:

    • 我尝试了您的解决方案,但在我将 2[0-4][0-9] 移到后面后它不会捕获 200-249
    • 啊,那么子程序只考虑第一种可能性。这很奇怪,但你在这里无能为力。试试^(?'a'2([0-4][0-9]|5[0-5]|1?[0-9]?[0-9]))\.(?&amp;a)$ 可能吗?
    • 我简单说一下;你的1?[0-9]?[0-9] 很烦人。将其全部分解为^(?'a'1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[0-9][0-9]|[0-9])\.(?&amp;a)$,您就可以使用它了。该问题似乎在您的引擎中的子程序和交替管理之间。 Nvm,Casimir的方案更好。
    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 2013-01-25
    • 2019-03-08
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2020-07-31
    • 2021-03-18
    相关资源
    最近更新 更多