2013-11-03 68 views
7

此:PHP undertsanding貪婪與nongreedy匹配

preg_match('~foo(.*?)(bar)?~','foo bar',$m); 

給了我這樣的:

Array 
(
    [0] => foo 
    [1] => 
) 

我有點糊塗了這一點。我得到那個組1給我一個空的字符串,因爲這是一個懶惰的匹配。但不應該(bar)?貪婪,因此給我捕獲組2?

似乎是合理的,我認爲我應該獲得是

Array 
(
    [0] => foo 
    [1] => 
    [2] => bar 
) 

其中[1]是一個空間。然而..這沒有發生。爲什麼?

+6

**焦點話題:**請將您的名字改爲'mysqli_noobie ...'。瞭解[*準備的語句*](http://j.mp/T9hLWi),並使用[PDO](http://php.net/pdo)或[MySQLi](http://php.net/mysqli ) - [這篇文章](http://j.mp/QEx8IB)將幫助你決定哪個。如果你選擇PDO,[這裏是一個很好的教程](http://j.mp/PoWehJ)。 – HamZa

+1

@HamZa這讓我輕笑! – IMSoP

+1

如果它按照您期望的方式工作,[0]實際上就是「富吧」。 [0]是完全匹配。 –

回答

5

這裏的答案非常簡單。第一組不匹配任何東西(第一遍),甚至沒有匹配空間。第二組試圖將空間與「酒吧」相匹配,當然這是失敗的。如果後面會有什麼東西需要匹配,引擎現在會回溯並擴展第一個捕獲組以匹配空間。但它現在的樣子非常好(第二組實際上可以是靜態的),所以它就保持這種狀態。

要產生你所期望的,試試這個:

preg_replace('~foo(.*?)(bar)?_~', 'foo bar_', $m); 


在你的編輯,你又增加了捕獲組。 (。*)現在是2.它會匹配到字符串的末尾,就像您認爲的那樣。所以你是對的,你只是改變了例子^^

+1

是啊我意識到,我發佈它後,然後明白它不是最後一個彈出「酒吧」,但'(。*)',謝謝! – slinkhi

3

不,這種行爲是正確的。從documentation on lazy matching

如果一個量詞後跟一個問號,那麼它變得懶惰,而是比賽的時間可能

最小數目由於(bar)?是可選的,(.*?)不需要匹配任何東西才能使正則表達式成功。由於foo之間的空格未被捕獲,因此表達式不能繼續並匹配bar

2

條目'0'始終是完全匹配的模式,在這種情況下是foo。 然而,第一個匹配組與*使用時沒有匹配。第二組是可選的。

+0

這並沒有真正回答這個問題。實際上,如果第一組不會懶惰,第二組將會捕獲該欄,儘管它仍然是可選的。 –

+0

@JohannesH。呵呵..'(foo)(。*)(bar)?'確實在'[2]'中給了我「吧」。爲什麼? – slinkhi

+1

這是因爲在這裏所有的捕獲組都是貪婪的。這意味着它們儘可能匹配。 (foo)與foo(在[1]中)匹配,當然。 (。*)匹配空格 - 和(bar)(在[2]中)。 (酒吧)?什麼都不匹配(所以沒有[3]) –