2011-02-09 129 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