2011-02-09 134 views
4

我与命名的子模式试验/ PHP中的PCRE“子程序”正则表达式的功能,我希望有人能解释一下下面的怪输出: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_matchpreg_match_all放“一”和“1”,但都仅包含一个空字符串。

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

我失去了一些东西在这里,或者我应该只是悼念什么,本来,继续前进?

回答

5

它的意义,这些子模式将无法捕捉到一群 - 他们的主要目的,它被使用超过一次,所以你不能真正抓住他们。此外,如果默认是捕获所有子模式它不会给你一个选择捕捉到一组,你不希望它 - 不是最好的默认行为。相反是微不足道的 - 您可以通过在(?&a)声明中添加另一个组来捕获。
我无法找到一个PCRE.org参照本。最接近的是这一点,这是相关的,因为你不直接匹配(?<a>...)(虽然你可能会想到一个空组):

任何捕获括号是 是在子程序调用过程中设置恢复到原来的值 后来。

这是对Perl manual更清晰(相关部分高亮显示):

这如何可能被用来作为一个例子如下:

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

需要注意的是内部匹配捕获缓冲器的递归在递归返回之后不可访问,所以需要额外的捕获缓冲层。

+1

是的,这是正确的;这是'(?(DEFINE)...)'的作用。它想要声明子例程。我有时会在定义之外使用全部大写命名捕获组,并将小写字母用于其内部的可召集的非捕获组,以帮助将两者保持在我的头脑中。看看给出的解决方案的更长时间[在这个答案](http://stackoverflow.com/questions/4284176/doubt-in-parsing-data-in-perl-where-am-i-going-wrong/4286326# 4286326)我如何在两种方式中使用命名组:调用和捕获。我从`%+`哈希中抽取的那些哈希,例如`$ + {VALUE}`或`@⁠+⁠{qw }`。 – tchrist 2011-02-09 11:32:58