需要正则表达式忽略括号之间的所有内容

时间:2012-02-11 00:45:24

标签: php regex

请考虑以下字符串

$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(或其他)字符包围。换句话说 - 我如何调整正则表达式以完全忽略大括号之间的任何内容?

3 个答案:

答案 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;

?>

但我必须承认使用正则表达式更优雅!