Regular Expressions: preg_replace only does one per line.

I am writing a little hack for a Wiki that enables highlighting of text using a background color. I use preg_replace to replace text delimited by ++ to insert the appropriate span. It works fine except for one thing, when there are multiple words highlighted in the same line, it only replaces the first and the last ++, leaving the middle ones intact and in effect it highlights the whole line from the first ++ to the last (with ++ as plain text in the middle). Here's the sample code

<?php
$text = "test  ++highlight!!++ test test test ++test++ highlight";

echo preg_replace('/\+\+(.*)\+\+/','<span style="background-color: #FFFF00">\\1</span>', $text);
?>

In this case, the first occurence of "highlight" and the last occurence of "test" should be highlighted (ie <span...>highlight</span>). If I insert a \n between the two words somewhere it works as it should.

I am not much of a regular expressions expert so could someone help me fix this one?
LVL 3
KvdnBergAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

hernst42Commented:
Try
echo preg_replace('/\+\+(.*)\+\+/U','<span style="background-color: #FFFF00">\\1</span>', $text);

notify the /U for ungreedy match of preg_replace
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
KvdnBergAuthor Commented:
Perfect, works like a charm but could you please explain in a little more detail why this works?
I usually just copy&paste regex things and adapt them without really understanding them.
0
frugleCommented:
preg_replace('/   #start
\+                      # escaped + matches a real +
\+                      # escaped + matches a real +
(.*)                    # everything up to the next match
\+                      # escaped + matches a real +
\+                      # escaped + matches a real +
/                        #stop
',

'replace with',                                    # \\1 is the contents of the first set of (brackets)

$variable_to_replace_in);

so, in English - look for the first two instances of the plus sign together then read everything until the next set of two plus signs.

Without the /U un-greedy flag, it sees the first and last double-plusses and highlights EVERYTHING in between them.

Mike
0
KvdnBergAuthor Commented:
Ok. I did some searching and found out myself. Normally PERL regular expressions are 'greedy', meaning they try to make the longest match possible. The U at the end of hernst42's answer means "ungreedy" so that it makes the shortest match possible. This can also be accomplished by putting a ? after the wildcard (*) like so:

echo preg_replace('/\+\+(.*?)\+\+/','<span style="background-color: #FFFF00">\\1</span>', $text);

See http://www.troubleshooters.com/codecorn/littperl/perlreg.htm#Greedy

0
hernst42Commented:
See http://de3.php.net/manual/en/reference.pcre.pattern.modifiers.php
the greedyness/ungreedines defines how many chars are used if * are given. The default is to match as many chars as along as the regex matches. If you use ungreedines it tries to match that expression with the minum characters.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.