2013-10-23 69 views
1

我有以下代碼:正則表達式多行太貪婪

$text = "Lorem ipsum dolor sit amet, [b]consectetur adipiscing elit[/b]. 
Nunc lorem velit, lacinia ut commodo in, suscipit vitae magna. 
Nam imperdiet neque blandit semper tempus. 
Curabitur sapien ante, vestibulum vitae ante a, condimentum dignissim tortor. Aenean adipiscing tincidunt lorem, non eleifend tellus suscipit a. Nulla convallis [b] 
pulvinar ligula[/b], at tempor ante. Fusce a tellus enim. Vivamus nibh eros, ultrices at auctor quis, fringilla nec dolor. Aenean nec tincidunt odio, id pulvinar felis. Pellentesque in augue volutpat, gravida nibh eu, lobortis augue."; 

preg_match_all("#(\[b\].*\[/b\])#s", $text, $value); 

$value從第一返回[B]最後[/ B]。我需要它來單獨匹配每一對。

據我所知,我不得不在最後使用s來選擇多行,但*然後是太貪婪。我不能只使用?,因爲我的字符數量可能會有所不同......我錯過了什麼?

回答

2

這是一個常見的錯誤。除非你做了一些事情來避免它,否則正則表達式引擎會找到可能被你的模式匹配的最長的子字符串。根據上下文,可能有各種可能的解決方案,但對於支持Perl正則表達式語法的引擎,最簡單的方法通常是使用您正在使用的重複操作符的「非貪婪」變體。即代替而不是*,+?而不是+,??而不是?{m,n}?而不是{m,n}

所以,在你的榜樣,模式應改爲:

preg_match_all("#(\[b\].*?\[/b\])#s", $text, $value); 
+0

有趣的是,我剛剛瞭解了*?和?? –

+0

但是,我們幾乎總是應該使用這些而不是那些貪婪的對應物,因爲它可以減少大量回溯的風險。 – jwatkins

+0

我從來沒有真正得到過正則表達式的頭,但我開始到達那裏。這工作的一種享受,似乎是有道理的。 – TH1981

1

的另一種方式,以避免惰性限定符:

preg_match_all('~\[b](?>[^[]++|\[(?!/b]))*+\[/b]~', $text, $value); 

有了這樣,就避免了兩個問題:

  1. 貪婪量詞不成問題,因爲角色類停在每個開口方括號
  2. 因爲你不使用點,你不關心's'修飾符和換行符。
+0

確實如此。但是非回溯羣體並沒有得到廣泛的支持,使用起來也更加困難。這是一個可以在任何正則表達式引擎中正常運行的替代方案(預計可能需要某些引擎進行一些語法替換或修改):'| \ [b \] [^ [] *(?:\ [(?:[^ b] | b [^]]))* \ [/ b \] | x' – jwatkins