Использование preg_split для движка шаблонов

#php #regex #templates #preg-split

#php #регулярное выражение #шаблоны #preg-split

Вопрос:

Я создаю механизм создания шаблонов и хотел бы разрешить вложенную логику.

Мне нужно разделить следующую строку, используя «@» для разделителя, но я хотел бы игнорировать этот разделитель — рассматривать как просто другой символ — если он внутри [квадратных скобок].

Вот входная строка:

 @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 — это то, что я ищу, но мог бы использовать помощь с регулярным выражением

Комментарии:

1. Это проблема без попытки?

2. попробовал следующий шаблон, но безрезультатно: /@ (?! [^[@]]*])/ x

Ответ №1:

Регулярное выражение:

 @(?> 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
]Ks*  # Match end of container block
 

Живая демонстрация

PHP:

 print_r(preg_split("~@(?>if|else(?>if)?)s*(?>([^()]* )s*)?[(?:[^][@]* (?>\.[^][@]*)*(@ (?!(?>if|else(?>if)?)))?|(?R))*]Ks*~", $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

Комментарии:

1. это идеально! работает и отличная ссылка на сайт, которая будет очень полезна. спасибо вам!! жаль, что у меня не было представителя для повышения

2. просто получил достаточно репутации для повышения и сделал, еще раз спасибо!

Ответ №2:

Чтобы сопоставить вложенные скобки, вам нужно использовать рекурсивный шаблон.

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

Он будет соответствовать каждому сегменту, не включая ведущий @ . Он также захватит последнюю скобку в группу 1, которую вы можете игнорировать.

Используйте шаблон с preg_match помощью или preg_match_all .

Ответ №3:

Спасибо за ответы! Ответ Revo сработал!

Я не смог сам придумать регулярное выражение и вместо этого создал функцию синтаксического анализа, которая также работает. Возможно, это может быть кому-то полезно:

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