【问题标题】:PCRE regular expressions using named pattern subroutines使用命名模式子例程的 PCRE 正则表达式
【发布时间】:2011-06-23 21:33:49
【问题描述】:

我正在尝试 PHP 的 PCRE 中的命名子模式/“子例程”正则表达式功能,我希望有人能解释以下奇怪的输出:

$re = "/
(?(DEFINE)
    (?<a> a )
)

^(?&a)$

/x";

var_dump(preg_match($re, 'a', $match)); // (int) 1 as expected
var_dump($match); // Array( [0] => 'a' ) <-- Why?

我不明白为什么命名组“a”不在结果中(内容为“a”)。将preg_match 更改为preg_match_all 会将“a”和“1”放入匹配数据中,但都只包含一个空字符串。

我真的很喜欢以这种方式编写正则表达式的想法,因为您可以使它们非常强大,同时保持它们非常易于维护(请参阅this answer 以获得一个很好的例子),但是如果子模式在匹配中不可用数据那么它真的没有多大用处。

我是在这里遗漏了什么,还是应该哀悼可能发生的事情并继续前进?

【问题讨论】:

    标签: php regex pcre


    【解决方案1】:

    这些子模式不会捕获一个组是完全有道理的——它们的主要目的是多次使用它,所以你不能真正捕获它们。此外,如果默认是捕获所有子模式,它不会为您提供选项not 来捕获您不想要的组 - 这不是最佳默认行为。相反是微不足道的 - 您可以通过在 (?&amp;a) 语句周围添加另一个组来捕获。
    我在PCRE.org 上找不到对此的参考。最接近的是这个,这是相关的,因为您不直接匹配(?&lt;a&gt;...)(尽管您可能期望一个空组):

    任何捕获括号 在子程序调用期间设置恢复到它们以前的值 之后。

    Perl manual 上更清楚(相关部分突出显示):

    如何使用它的示例如下:

    /(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT))
    (?(DEFINE)
    (?<NAME_PAT>....)
    (?<ADRESS_PAT>....)
    )/x
    

    请注意,递归内部匹配的捕获缓冲区在递归返回后无法访问,因此需要额外的捕获缓冲区层。

    【讨论】:

    • 是的,没错;这就是(?(DEFINE)…) 的工作原理。它想声明子程序。我有时对定义之外的命名捕获组使用全大写,对其中的可调用非捕获组使用小写,以帮助将两者保持在我的脑海中。查看in this answer 给出的解决方案中更长的解决方案,了解我如何以两种方式使用命名组:调用和捕获。我从%+ 哈希中提取的捕获的,例如$+{VALUE}@⁠+⁠{ qw&lt; TAG BODY &gt; }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    相关资源
    最近更新 更多