2012-05-11 51 views
5

基本上,我想要做的是通過一個相當大的PHP文件進行搜索,並替換任何包含字符串「search_term」的PHP代碼塊與其他一些代碼。即匹配最接近的字符串與搜索詞(perl正則表達式)

<?php 
//some stuff 
?> 
<?php 
// some more stuff 
$str = "search_term"; 
// yes... 
?> 
<?php 
// last stuff 
?> 

應該成爲

<?php 
//some stuff 
?> 
HELLO 
<?php 
// last stuff 
?> 

到目前爲止,我已經得到了什麼是

$string =~ s/<\?php(.*?)search_term(.*?)\?>/HELLO/ims; 

這正確匹配最接近收盤?>,但在第一個<?php開始比賽,而不是最接近字符串search_term的那個。

我在做什麼錯?

回答

5

一般來說,我不喜歡使用非貪婪匹配,因爲它通常會導致類似的問題。 Perl會查看您的文件,找到第一個'<?php',然後開始查找其餘的正則表達式。它通過第一個'?>'和第二個'<?php',因爲它們匹配.*,然後找到search_term和下一個'?>',並且完成了。

非貪婪匹配意味着你有一個正則表達式匹配比你真正想要的東西更多的東西,並且它留給perl來決定返回哪個匹配。最好使用正好匹配你想要匹配的正則表達式。在這種情況下,你可以得到你使用((?!\?>).)*代替.*?想要的東西((?!\?>)是負先行斷言)

s/<\?php((?!\?>).)*search_term((?!\?>).)*\?>/HELLO/is; 

如果您預計多場比賽,你可能想使用/isg而非/is

@blocks = split /(\?>)/, $string; 
while (@blocks) { 
    $block = shift @blocks; 
    $sep = shift @blocks; 
    if ($block=~/search_term/) { 
     print "HELLO"; 
    } else { 
     print $block, $sep; 
    } 
} 
+0

謝謝。在我特殊的情況下,這個塊的東西確實很理想 – Mala

2

你只需要把你的第一個捕獲組放回你的替換。事情是這樣的:

s/<\?php(.*)<\?php(.*?)search_term(.*?)\?>/<\?php$1HELLO/ims 
+0

剛剛試過這個......它沒有擺脫'search_term' – Mala

+0

hooray之前的部分!使用它:'s/<\?php(。*)<\?php(。*?)search_term(。*?)\?>/<\?php $ 1HELLO/ims' – Mala

+0

爲後人。 – Benj

0

您正在使用貪婪小氣匹配,但仍可以匹配太多。

Matching repetitions in perlretut描述得很好。

我有時使用否定匹配來幫助,但我不認爲這會有所幫助。例如:

s/^[^A]*A/A/ 

確保我的字符不匹配。

但我通常不想跨越多行,除非必須,否則不使用perl。

+0

呃在哪裏? '。*?'是非貪婪的。 – Benj

+0

是的。我錯了,但肯定會比想要的更多。 – Julian

1
s/(.*)<\?php.*?search_term.*?\?>/${1}HELLO/ims; 

在你的正則表達式,正則表達式引擎試圖找到你的目標表達式匹配的子最早出現時,它會找出它的第<?php和第二?>之間。

通過將(.*)在正則表達式的開始,你欺騙正則表達式引擎喜歡去字符串的結束(因爲.*整個字符串相匹配),然後回溯到景點在那裏可以找到字符串「<?php」 。這樣,結果匹配將不包括任何更多的<?php令牌。

+0

**如果**只想替換一個代碼塊,這將比@Benj's更好。但這不是我讀這個問題的方式。 –

2
$string =~ s/<\?php(?:(?!\?>|search_term).)*search_term.*?\?>/HELLO/isg; 

(?:(?!\?>|search_term).)*匹配一個字符確保字符不是?>search_term開始後的時間,:

或者,只是將文件分塊分割。當停止匹配時,如果字符串中的下一個事件是search_term,則它將消耗該事件及其後的所有內容,直到下一個?>。否則,該嘗試失敗,並在下一個<?php重新開始。

關鍵的一點是,就像@ RobertYoung的解決方案一樣,在搜索search_term時,不允許匹配?>。通過不匹配search_term,它消除了回溯,這使搜索更有效率。取決於可能無關緊要的源字符串的大小,但它也不會明顯地損害性能。

@ Benj的解決方案(當前發佈)不起作用。它可以提供您提供的樣本字符串所需的輸出,但這只是偶然。它只取代最後的代碼塊,其中search_term,並且(如@mob註釋)它完全忽略了第一個代碼塊的內容。