All All - 5 months ago 8
PHP Question

How to edit text between tags with PHP

I want to capture number range and replace it with the numbers, but only within a specific tag.

$str = "This is some (the numbers are between 8, 9-12) and we have some 9-12 outside";


The output should be

$str = "This is some (the numbers are between 8, 9, 10, 11, 12) and we have some 9-12 outside";


I need to capture only
9-12
, which is between parenthesis, and only replace it not
9-12
outside parenthesis.

Answer

You can do it like this with preg_replace_callback and a \G based pattern:

$str='This is some (the numbers are between 8, 9-12) and we have some 9-12 outside';

echo preg_replace_callback('~(?:\G(?!\A)|\()[^)0-9]*+(?:[0-9]++(?!-[0-9])[^)0-9]*)*+\K([0-9]++)-([0-9]+)~', function ($m) {
    return implode(', ', range($m[1], $m[2]));
}, $str);

Pattern details:

~
(?:  # two possible beginnings
    \G(?!\A)  # position after the previous match
  |           # OR
    \(        # an opening parenthesis
)
[^)0-9]*+ # all that is not a closing parenthesis or a digit 
(?:
    [0-9]++ (?!-[0-9]) # digits not followed by an hyphen and a digit
    [^)0-9]*
)*+
\K  # the match result starts here
([0-9]++) # group 1
-
([0-9]+)  # group 2
~

If you want to limit the number of steps to obtain a match, you can rewrite the beginning of the pattern: (?:\G(?!\A)|\() like this: \G(?:(?!\A)|[^(]*\(). In this way, the pattern will no more fail until an opening parenthesis but will quickly reach it avoiding (limiting) the cost of a (most of the time) failing alternation at the start of the pattern.

Comments