preg_replace() catch the first match

Viewed 62

I am replacing some code to del and ins html tag using PHP.

For example, my code is:

$text = 'This is (foo)((bar))';

$text = preg_replace('/\((.*)\)*/', '<del>$1</del>', $text);
$text = preg_replace('/\(\((.*)\)\)/', '<ins>$1</ins>', $text);

Output I get:

This is <del>foo)((bar)</del>

Which means, it catches the last closing bracket.

Output I want:

This is <del>foo</del><ins>bar</ins>

Thwn, how to catch the first closing bracket?

Yes, I can solve it by replacing ins tag first like this:

$text = 'This is (foo)((bar))';

$text = preg_replace('/\(\((.*)\)\)/', '<ins>$1</ins>', $text);
$text = preg_replace('/\((.*)\)*/', '<del>$1</del>', $text);

But is there any better solution without moving like this?

1 Answers

If your only use of parentheses is for tags, you could just use strtr:

$text = 'This is (foo)((bar))';

$text = strtr($text, array('(' => '<del>', ')' => '</del>', '((' => '<ins>', '))' => '</ins>'));
echo $text;

Output:

This is <del>foo</del><ins>bar</ins>

strtr works in this situation because it replaces the longer strings in the array first so any ((...)) will be replaced with ins tags before the string is parsed for (...) to replace with del tags.

Otherwise, you will need to check that the opening ( is not preceded or followed by another ( when replacing with del tags, which you can do with negative lookarounds:

$text = preg_replace('/(?<!\()\((?!\()([^)]*)\)/', '<del>$1</del>', $text);
$text = preg_replace('/\(\(([^)]*)\)\)/', '<ins>$1</ins>', $text);
echo $text;

Output:

This is <del>foo</del><ins>bar</ins>

Demo on 3v4l.org

Note that using [^)]*\) is more efficient than .*?\) due to contrast.

Related