Reputation: 4099
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
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
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
Reputation: 1839
(?<!{)(?>[0-9]+(?:\.[0-9]+)?)(?!})
Atomic grouping. And perhaps lookbehind isn't really needed.
Upvotes: 3