将最接近的字符串与搜索词匹配(perl regex)

Mal*_*ala 5 regex perl replace

基本上,我要做的是搜索一个相当大的PHP文件,并用其他代码替换包含字符串"search_term"的任何PHP代码块.即

<?php
//some stuff
?>
<?php
// some more stuff
$str = "search_term";
// yes...
?>
<?php 
// last stuff
?>
Run Code Online (Sandbox Code Playgroud)

应该成为

<?php
//some stuff
?>
HELLO
<?php 
// last stuff
?>
Run Code Online (Sandbox Code Playgroud)

到目前为止我得到的是

$string =~ s/<\?php(.*?)search_term(.*?)\?>/HELLO/ims;
Run Code Online (Sandbox Code Playgroud)

这与最接近的闭合正确匹配?>,但在最开始时匹配<?php,而不是最接近字符串的匹配search_term.

我究竟做错了什么?

Rob*_*ung 5

一般来说,我不喜欢使用非贪婪匹配,因为它通常会导致这样的问题.Perl查看你的文件,找到第一个'<?php',然后开始寻找其余的regexp.它通过第一个'?>'和第二个'<?php'因为它们匹配.*,然后找到search_term和下一个'?>',它就完成了.

非贪婪匹配意味着你有一个正常的表达式,它匹配的东西比你真正想要的更多,并且它将它留给perl来决定返回哪个匹配.最好使用与您想要匹配的正则匹配的正则表达式.在这种情况下,您可以使用((?!\?>).)*而不是.*?((?!\?>)是一个负面的前瞻断言)来获得您想要的内容

s/<\?php((?!\?>).)*search_term((?!\?>).)*\?>/HELLO/is;
Run Code Online (Sandbox Code Playgroud)

如果您希望多次匹配,则可能需要使用/isg而不是/is.

或者,只需将文件拆分为块:

@blocks = split /(\?>)/, $string;
while (@blocks) {
    $block = shift @blocks;
    $sep = shift @blocks;
    if ($block=~/search_term/) {
        print "HELLO";
    } else {
        print $block, $sep;
    }
}
Run Code Online (Sandbox Code Playgroud)