You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP模板编译器@if指令正则问题:如何匹配递归括号内容?

解决PHP模板@if指令括号匹配问题

你的问题根源是原正则未处理括号的嵌套(哪怕是单层闭合括号),导致提前截断了条件内容。这里给你两个可行的解决方案:

方案一:修正正则表达式(支持嵌套括号、全局多行匹配)

用PCRE的平衡组语法可以精准匹配括号内的完整条件,同时兼容全局和多行场景:

代码实现

public function handleIf($content) {
    // 核心正则:匹配@if(...),支持嵌套括号,带全局/多行修饰符
    $pattern = '/@if\(\s*( (?&expr) )\s*\)/xms';
    
    // 定义平衡组规则,匹配合法的PHP表达式(含任意嵌套括号)
    $pattern .= '
        (?(DEFINE)
            (?<expr> 
                (?: 
                    [^()]+ 
                    | 
                    \( (?&expr) \) 
                )* 
            )
        )
    ';
    
    // 替换为标准PHP if结构
    return preg_replace($pattern, '<?php if($1) { ?>', $content);
}

关键说明

  • (?&expr) 递归引用预定义的表达式规则,完美处理嵌套括号(比如@if( (a > b) && !empty($c) ))
  • /xms 修饰符:x忽略正则中的空白(方便写注释),m启用多行模式,s让.匹配换行符
  • \s* 忽略括号前后的空白,兼容@if( !empty($title) )这类带空格的写法

测试你的示例@if(!empty($title)),会正确输出<?php if(!empty($title)) { ?>。


方案二:词法分析(Tokenize)

如果你的模板会用到复杂表达式(比如多嵌套括号、逻辑运算符组合),正则可能仍有局限,推荐用PHP自带的语法分析器处理:

代码实现

public function parseIfDirective($content) {
    $offset = 0;
    while (($pos = strpos($content, '@if(', $offset)) !== false) {
        $start = $pos + 4; // 跳过"@if("的长度
        // 借助PHP的tokenizer解析表达式
        $tokenStream = token_get_all('<?php ' . substr($content, $start));
        
        $parenCount = 1;
        $endOffset = $start;
        
        foreach ($tokenStream as $token) {
            if (is_array($token)) {
                $endOffset += strlen($token[1]);
            } else {
                if ($token === '(') $parenCount++;
                if ($token === ')') $parenCount--;
                $endOffset++;
            }
            
            // 找到匹配的闭合括号时停止
            if ($parenCount === 0) break;
        }
        
        // 提取完整条件内容
        $condition = substr($content, $start, $endOffset - $start - 1);
        // 替换为标准PHP if语法
        $replaceStr = "<?php if($condition) { ?>";
        $content = substr_replace($content, $replaceStr, $pos, $endOffset - $pos);
        
        // 更新偏移量,继续处理下一个@if
        $offset = $pos + strlen($replaceStr);
    }
    return $content;
}

这种方法直接利用PHP的语法解析能力,完全避免正则的匹配盲区,适合复杂模板场景。


内容的提问来源于stack exchange,提问作者Splashsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:35:03