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

con*_*nec 5 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?
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么命名组"a"不在结果中(内容为"a").更改preg_matchpreg_match_all在匹配数据中放置"a"和"1",但两者仅包含空字符串.

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

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

Kob*_*obi 5

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

在子例程调用期间设置的任何捕获括号都会在之后恢复为之前的值.

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

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

/(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT))
(?(DEFINE)
(?<NAME_PAT>....)
(?<ADRESS_PAT>....)
)/x
Run Code Online (Sandbox Code Playgroud)

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