使用命名模式子例程的PCRE正则表达式

时间:2011-02-09 04:16:32

标签: php regex pcre

我正在试验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以获得一个很好的例子),但如果子模式不可用匹配数据然后真的没什么用。

我在这里遗漏了什么或者我应该哀悼本来可以继续下去的事情吗?

1 个答案:

答案 0 :(得分:5)

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

  

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

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

  

如何使用它的一个例子如下:

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

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