Multiple preg_match_all on same line

Any questions involving matching text strings to patterns - the pattern is called a "regular expression."

Moderator: General Moderators

Post Reply
angrycat
Forum Newbie
Posts: 2
Joined: Thu Apr 17, 2008 11:14 am

Multiple preg_match_all on same line

Post by angrycat »

Hello All,

I am trying to use regex to replace multiple values in a string, which all use the same de-limiter.

I have the following small function to do this:

Code: Select all

function embeded($retval){    
    while (preg_match_all("|#(.*)#|", $retval, $out)){          
        $retval = preg_replace("|#(.*)#|", "replacement text", $retval);
    } 
    return $retval;
}
If I pass the following string into that function:

"some text #replace 1# and some more text"

Then it works fine, however, if I try and pass

"some text #replace 1# and some more text #replace 2# and even more text"

then the function fails, because, instead of evaluating #replace 1# and then evaluating #replace 2#

it actually evaluates:

#replace 1# and some more text #replace 2#

i.e. it is evaluating on the two outermost "#" characters.

Is it possible to get it to evaluate the first pair of # characters, then the second pair and so on?

I have read the documentation and just cannot figure it, if anyone can help me out I would be very grateful!

Thanks!
angrycat
Forum Newbie
Posts: 2
Joined: Thu Apr 17, 2008 11:14 am

Re: Multiple preg_match_all on same line

Post by angrycat »

I have a work around:

Code: Select all

function embeded($retval){   
    $words = explode(" ", $retval); 
    foreach ($words as $word){
        if (preg_match_all("|#(.*)#|", $word, $out)){
            $retval = str_replace($word, " replacement ", $retval);
        }
    }
    return $retval;
}
but if anyone knows how to do this with regex as originally posted I would be interested to hear it!
User avatar
prometheuzz
Forum Regular
Posts: 779
Joined: Fri Apr 04, 2008 5:51 am

Re: Multiple preg_match_all on same line

Post by prometheuzz »

That is because the #(.*) is greedy: it matches an # and then as much as possible (until the end of the string), and then backtracks back to find a #. So "#replace 1# and some more text #replace 2#" is matched. Two options:

1 - Make it not greedy (reluctant) by adding a question mark behind the .*:

Code: Select all

 
function embeded($retval){    
    return preg_replace('/#.*?#/', 'REPLACEMENT', $retval);
}
 


2 - The more preferred option: make your regex more specific by matching "zero or more non-# characters" ([^#]*)

Code: Select all

 
function embeded($retval){    
    return preg_replace('/#[^#]*#/', 'REPLACEMENT', $retval);
}
 
Post Reply