2012-05-11 55 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注释)它完全忽略了第一个代码块的内容。