matching the closest strings to a search term (perl regex)

perl, regex, replace

Solution

Generally, I don't like to use non-greedy matching, because it usually leads to problems like this. Perl looks at your file, finds the first `'<?php'`, then starts looking for the rest of the regexp. It passes over the first `'?>'` and the second `'<?php'` because they match `.*`, then finds `search_term` and the next `'?>'`, and it's done.

Non-greedy matching means that you have a regular expression that matches more things than you really want, and it leaves it up to perl to decide which match to return. It's better to use a regular expression that matches exactly what you want to match. In this case, you can get what you want by using `((?!\?>).)*` instead of `.*?` (`(?!\?>)` is a negative look-ahead assertion)

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

If you expect multiple matches, you might want to use `/isg` rather than `/is`.

Alternatively, just split the file into blocks:

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

Problem

Basically, what I'm trying to do is search through a rather large PHP file, and replace any block of PHP code that includes the string "search_term" somewhere in it with some other code. I.e. ``` <?php //some stuff ?> <?php // some more stuff $str = "search_term"; // yes... ?> <?php // last stuff ?> ``` should become ``` <?php //some stuff ?> HELLO <?php // last stuff ?> ``` What I've got so far is ``` $string =~ s/<\?php(.*?)search_term(.*?)\?>/HELLO/ims; ``` This correctly matches the closest closing `?>`, but begins the match at the very first `<?php`, instead of the one closest to the string `search_term`. What am I doing wrong?

Original source