请考虑以下字符串
$text = "Dat foo 13.45 and $600 bar {baz:70} and {8}";
我需要在$ text中标记所有数字,除非它们在花括号之间。我现在有这个:
preg_replace("/(?<!{)([0-9]+(?:\.[0-9]+)?)(?!})/","{NUMBER:$0}",$text);
输出:
Dat foo {NUMBER:13.45} and $ {NUMBER:600} bar {baz: {NUMBER:7} 0} and {8}
但是,所需的输出是:
Dat foo {NUMBER:13.45} and ${NUMBER:600} bar {baz:70} and {8}
其中{和}之间的数字被忽略,即使它们被alfanumerical(或其他)字符包围。换句话说 - 我如何调整正则表达式以完全忽略大括号之间的任何内容?
答案 0 :(得分:3)
(?<!{)(?>[0-9]+(?:\.[0-9]+)?)(?!})
Atomic grouping. 也许真的不需要背后隐藏。
答案 1 :(得分:2)
您可以这样使用/e
:
preg_replace("/(\\d+(?:\\.\\d+)?)|{[^}]+}/e", '"$1"?"{NUMBER:$1}":"$0"', $text);
结果是:
Dat foo {NUMBER:13.45} and ${NUMBER:600} bar {baz:70} and {8}
如果{groups}
始终保持平衡且任何地方都没有松散的{}
,那么这样的替代黑客就会有效:
preg_replace("/\\d+(?:\\.\\d+)?(?![^{}]*})/", '{NUMBER:$0}', $text);
但第一个解决方案是更好的imo。
答案 2 :(得分:0)
您可以实现一个简单的解析器:
<?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;
?>
但我必须承认使用正则表达式更优雅!