与PHP / Regex匹配的智能括号

时间:2018-06-27 19:17:33

标签: php regex

我很想在代码块中突出显示函数的用法。 例如,看下面的示例代码中的fwrite()实例:

Simple

一个简单的preg_replace,我可以突出显示该功能:

$sample = preg_replace("/fwrite\((.*)\)\;?/U", "<code>$0</code>", $sample);

但是,如果该函数包含嵌套的括号,它将变得更加棘手。

如果是代码示例,则为:

More complex

...那么正则表达式模式将不知道fwrite()函数内部的内容不是该函数的结束。

2 个答案:

答案 0 :(得分:1)

在第二个示例中,它在第一个)(括号)处停止,因为表达式上带有U(不整洁)标志。因此,它不再是默认的匹配行为,而是“惰性”并且尽可能少地匹配。要解决此问题,只需删除U标志。

然后,我们必须解决以下事实:您的第一个示例从比赛中排除了;(分号)。这是因为您有?量词,以惰性(尽可能少,包括零)的方式与前面的字符匹配0或1次。要在删除U标志后获得此行为,我们必须添加第二个?,然后将默认行为从贪婪翻转为懒惰。

将它们放在一起,您应该得到:

$sample = preg_replace("/fwrite\((.*)\)\;??/", "<code>$0</code>", $sample);

DEMO

答案 1 :(得分:0)

解决方案:

1)计数打开和关闭:

function highlightcode($fn, $sample){
    $fn = rtrim($fn, ")");
    if(!$pos = $start = strpos($sample, $fn)) return($sample); //not found
    $opens = 1; $pos += strlen($fn);
    while($pos < strlen($sample)){
        $char = substr($sample, $pos, 1);
        $opens += ($char == "(" ? 1 : ( $char == ")" ? -1 : 0));
        //echo "POS: $pos CHAR: $char OPENS: $opens<br />";
        if($opens < 1){ $end = $pos; break; }
        $pos++;
    }
    return(substr($sample, 0, $start) . "<code>" . substr($sample, $start, ($end - $start)) . "</code>" . substr($sample, $end));
}

echo highlightcode("eval()", $sample);

2)正则表达式:

function highlightcode($fn, $sample){
    $fn = rtrim($fn, "()");
    $pattern = '~' . $fn . '(?= ( \( (?: [^()]+ | (?1) )*+ \) ) )~x';
    if(!preg_match_all($pattern, $sample, $matches)) return( $sample );
    foreach($matches[1] as $m){
        $find = "{$fn}{$m}";
        $repl = "<code>{$find}</code>";
        $sample = str_replace($find, $repl, $sample);
    }
    return( $sample );
}

echo highlightcode("eval()", $sample);