代码之家  ›  专栏  ›  技术社区  ›  yevg

使用preg_split作为模板引擎

  •  0
  • yevg  · 技术社区  · 8 年前

    我正在构建一个模板引擎,并希望允许嵌套逻辑。

    我需要使用“@”作为分隔符拆分以下字符串,但希望忽略此分隔符-将其视为另一个字符-如果它位于[方括号]内。

    以下是输入字符串:

    @if(param1>=7) [ something here @if(param1>9)[ nested statement ] ] @elseif(param2==true) [ 2st condition true ] @else [ default condition ] 
    

    结果应该如下所示:

    array(
    
       " if(param1>=7) [ something here @if(param1>9)[ nested statement ] ] ",
    
       " elseif(param2==true) [ 2st condition true ] ",
    
       " else [ default condition ] "
    
    )
    

    我相信preg_split是我要找的,但是可以使用regex的帮助

    3 回复  |  直到 8 年前
        1
  •  1
  •   revo shanwije    8 年前

    正则表达式:

    @(?> if | else (?>if)? ) \s*  # Match a control structure
    (?> \( [^()]*+ \) \s*)?  # Match statements inside parentheses (if any)
    \[  # Match start of block
    (?:
        [^][@]*+  # Any character except `[`, `]` and `@`
        (?> \\.[^][@]* )* (@+ (?! (?> if | else (?>if)? ) ) )? # Match escaped or literal `@`s
        |  # Or
        (?R)  # Recurs whole pattern
    )*  # As much as possible
    \]\K\s*  # Match end of container block
    

    Live demo

    PHP:

    print_r(preg_split("~@(?>if|else(?>if)?)\s*(?>\([^()]*+\)\s*)?\[(?:[^][@]*+(?>\\.[^][@]*)*(@+(?!(?>if|else(?>if)?)))?|(?R))*\]\K\s*~", $str, -1, PREG_SPLIT_NO_EMPTY));
    

    Array
    (
        [0] => @if(param1>=7) [ something here @if(param1>9)[ nested statement ] ]
        [1] => @elseif(param2==true) [ 2st condition true ]
        [2] => @else [ default condition ]
    )
    

    PHP live demo

        2
  •  0
  •   Markus Jarderot    8 年前

    要匹配嵌套括号,需要使用递归模式。

    (?:(\[(?:[^[\]]|(?1))*])|[^@[\]])+
    

    它将匹配每个段,不包括前导段 @ 它还将捕获组1中的最后一个括号,您可以忽略它。

    使用模式 preg_match preg_match_all .

        3
  •  0
  •   yevg    8 年前

    感谢您的回复!雷沃的回答奏效了!

    我自己无法提出正则表达式,而是构建了一个同样有效的解析器函数。也许它对某些人有用:

    function parse_context($subject) { $arr = array(); // array to return
    
        $n = 0;  // number of nested sets of brackets
        $j = 0;  // current index in the array to return, for convenience
    
        $n_subj = strlen($subject);
        for($i=0; $i<$n_subj; $i++){
            switch($subject[$i]) {
                case '[':
                    $n++;
                    $arr[$j] .= '[';
                    break;
                case ']':
                    $n--;
                    $arr[$j] .= ']';
                    break;
                case '@':
                    if ($n == 0) {
                        $j++;
                        $arr[$j] = '';
                        break;
                    }
                default: $arr[$j].=$subject[$i];
            }
        }
        return $arr;
    
    } // parse_context()