Pr0no
Pr0no

Reputation: 4099

Need regex to ignore everything that is between brackets

Please consider the following string

$text = "Dat foo 13.45 and $600 bar {baz:70} and {8}";

I need to label all numbers in $text, except for when they are between curly braces. I now have this:

preg_replace("/(?<!{)([0-9]+(?:\.[0-9]+)?)(?!})/","{NUMBER:$0}",$text);

which outputs:

Dat foo {NUMBER:13.45} and $ {NUMBER:600} bar {baz: {NUMBER:7} 0} and {8}

However, the desired output is:

Dat foo {NUMBER:13.45} and ${NUMBER:600} bar {baz:70} and {8}

where numbers between { and } are ignored, even if they are surrounded by alfanumerical (or other) characters. In other words - how do I need to adjust the regex to completely ignore whatever there is between curly braces?

Upvotes: 0

Views: 1596

Answers (3)

Nir Alfasi
Nir Alfasi

Reputation: 53525

you can implement a simple parser instead:

<?php
function parse($str){
    $res = "";
    $tmp_res = "";
    $ignore = false;
    for ($i = 0; $i < strlen($str); $i++) {
        $char = $str[$i];
        if ($char === "{" ){
            while ($char != "}" ){
                $res = $res . $char;
                $i++;
                $char = $str[$i];
            }
        }
        if(is_numeric($char)){
            $res = $res . "{NUMBER:$char";
            $i++;
            $char = $str[$i];
            while (is_numeric($char) || $char == '.'){
                $res = $res . $char;
                $i++;
                $char = $str[$i];
            }
            $res = $res . "}" . $char; // add the "}"
        }
        else{
            $res = $res . $char;
        }
    }
    return $res;
}

$text = parse("Dat foo 13.45 and $600 bar {baz:70} and {8}");
echo $text;

?>

but I must admit that using regex is more elegant!

Upvotes: 0

Qtax
Qtax

Reputation: 33908

You could use /e in this way:

preg_replace("/(\\d+(?:\\.\\d+)?)|{[^}]+}/e", '"$1"?"{NUMBER:$1}":"$0"', $text);

Result being:

Dat foo {NUMBER:13.45} and ${NUMBER:600} bar {baz:70} and {8}

An alternative hack like this would work if {groups} are always balanced and there are no loose {} anywhere:

preg_replace("/\\d+(?:\\.\\d+)?(?![^{}]*})/", '{NUMBER:$0}', $text);

But the first solution is nicer imo.

Upvotes: 2

user1096188
user1096188

Reputation: 1839

(?<!{)(?>[0-9]+(?:\.[0-9]+)?)(?!})

Atomic grouping. And perhaps lookbehind isn't really needed.

Upvotes: 3

Related Questions