与PHP/Regex匹配的智能括号

与PHP/Regex匹配的智能括号,php,regex,Php,Regex,我想在代码块中强调函数的用法。 例如,在以下示例代码中查看fwrite的实例: 一个简单的preg_替换,我可以突出显示该功能: $sample = preg_replace("/fwrite\((.*)\)\;?/U", "<code>$0</code>", $sample); 但是,如果函数包含嵌套的圆括号,则会变得更加棘手 如果代码示例为: 。。。然后正则表达式模式将不知道fwrite函数中的内容不是函数的结束。在第二个示例中,它在第一个括号处停止,因为表达式上有

我想在代码块中强调函数的用法。 例如,在以下示例代码中查看fwrite的实例:

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

$sample = preg_replace("/fwrite\((.*)\)\;?/U", "<code>$0</code>", $sample);
但是,如果函数包含嵌套的圆括号,则会变得更加棘手

如果代码示例为:


。。。然后正则表达式模式将不知道fwrite函数中的内容不是函数的结束。

在第二个示例中,它在第一个括号处停止,因为表达式上有U ungreedy标志。因此,与尽可能多地匹配的默认行为不同,它现在是懒惰的,并且匹配尽可能少。要解决此问题,只需删除U标志

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

把这些放在一起,你应该得到:

$sample = preg_replace("/fwrite\((.*)\)\;??/", "<code>$0</code>", $sample);
解决方案:

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);

您能否包含$sample以便我们可以使用实际字符串?我们无法处理图像。这似乎与这里已经回答的另一个问题有关:是否要求结尾处的分号不是全部匹配的一部分?@PatrickQ,不,不是必需的。@BenCoffin,您是否可以控制$sample的文本/内容?我之所以这样问,是因为您更新的测试不匹配是因为它在函数调用后没有分号。如果您能够在本文中添加分号,那么我将更新我的答案,以反映将起作用的更改。如果你不是,那么你的问题会变得更复杂,你应该看到。太棒了。我可以确认@patrick-q提供的解决方案是完美的。