#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 ]
)
Комментарии:
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()