preg_replace() catch the first match

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?

Upvotes: 2

Views: 85

Answers (1)

Nick
Nick

Reputation: 147146

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.

Upvotes: 3

Related Questions