Reputation: 29
I have a problem with BBCodes - this preg_replace
does not work as intended:
$message = preg_replace("/\[color=(\#[0-9A-F]{6}|[a-z]+)\](.*)\[\/color\]/Usi", "<span style=\"color:\\1\">\\2</span>", $message);
This works correctly:
[color=#ff0000]text text text text text[/color]
[color=#00ffff]texttexttext[/color]
Result:
But if there are two color tags one after another, it does not work correctly:
[color=#ff0000][color=#00ffff]text text text text text[/color] [/color]
[color=#ff0000]text text text[color=#00ffff]text text text text text[/color] [/color]
Result:
Upvotes: 0
Views: 140
Reputation: 29667
You could also just do it via 2 replacements. One for the opening, one for the closing tag.
The nesting of those color tags won't matter then.
$message = preg_replace('%\[color=(\#[0-9A-F]{6}|[a-z]+)\]%i', '<span style="color:$1">', $message);
$message = preg_replace('%\[/color\]%i', '</span>', $message);
Or in 1 statement:
$message = preg_replace(
[ '%\[color=(\#[0-9A-F]{6}|[a-z]+)\]%i',
'%\[/color\]%i'
],
[ '<span style="color:$1">',
'</span>'
], $message);
As pointed out by Casimir et Hippolyte, not considering the nesting could give bad results.
So here's another method that uses a while loop and a recursive regex:
$pattern = '%\[color=(\#[0-9A-F]{6}|[a-z]+)\].*?(((?R)|.)*?)\[\/color\]%i';
$replacement = '<span style="color:$1">$2</span>';
do {
$message = preg_replace($pattern, $replacement, $message, -1, $count);
} while ($count);
Upvotes: 2
Reputation: 1818
Actually, in the string [color=#ff0000][color=#00ffff]text text text text text[/color] [/color]
your regular expression matches the first openning with the first closing tags. One way to avoid this is to slightly modify your regexp, for example:
/\[color=(\#[0-9A-F]{6}|[a-z]+)\]([^[]*)\[\/color\]/
Then it will only match the most nested tags. You need to do this in a loop, while your string contains bbcodes.
Upvotes: 1