yoyoyo
yoyoyo

Reputation: 29

Bbcode parser does not work correctly

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:

Correct 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:

Incorrect resul

Upvotes: 0

Views: 140

Answers (2)

LukStorms
LukStorms

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

Nina Lisitsinskaya
Nina Lisitsinskaya

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

Related Questions