我正在试验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以获得一个很好的例子),但如果子模式不可用匹配数据然后真的没什么用。
我在这里遗漏了什么或者我应该哀悼本来可以继续下去的事情吗?
答案 0 :(得分:5)
这些子模式不会捕获一个组是完全合理的 - 它们的主要目的是不止一次使用它,所以你无法真正捕获它们。此外,如果默认设置是捕获所有子模式,则它不会为您提供选项而不是来捕获您不希望它的组 - 而不是最佳默认行为。相反的是微不足道的 - 您可以通过在(?&a)
语句周围添加另一个组来捕获
我在PCRE.org上找不到对此的引用。最接近的是,这是相关的,因为您不直接匹配(?<a>...)
(尽管您可能期望一个空组):
任何捕获括号 在子程序调用期间设置恢复为先前的值 之后。
Perl manual(相关部分突出显示)更清晰:
如何使用它的一个例子如下:
/(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT)) (?(DEFINE) (?<NAME_PAT>....) (?<ADRESS_PAT>....) )/x
请注意,在递归返回后,无法访问在递归内匹配的捕获缓冲区,因此需要额外的捕获缓冲层。