Использование переменных регулярных выражений в preg_match_all

Я создаю синтаксический анализатор псевдопеременных на PHP, чтобы обеспечить чистый и простой синтаксис в представлениях, и реализовал механизм для операторов if. Теперь я хочу иметь возможность использовать вложенные операторы if, и самым простым и элегантным решением, которое я придумал, было использование идентификации в качестве маркера для блока.

Итак, это в основном макет, который я ищу в представлении:

{if x is empty}
    {if y is array}
        Hello World
    {endif}
{endif}

Сценарий найдет первый оператор if и сопоставит его с оператором endif на той же глубине. Если он оценивается как true, внутренний блок также будет проанализирован.

Теперь у меня возникли проблемы с настройкой регулярного выражения для использования глубины в следующем коде:

preg_match_all('|([\t ]?){if (.+?) is (.+?)}(.+?){endif}|s', $template, $match);

По сути, я хочу, чтобы первое совпадение в ([\t ]?) было помещено перед {endif} с использованием какой-то переменной, и убедиться, что выражение не будет полным, если нет совпадения {endif} на той же глубине, что и {if ...}.

Можете ли вы помочь мне завершить его?


person Christoffer    schedule 17.11.2009    source источник
comment
Есть ли причины, по которым вы не хотите использовать один из них? webresourcesdepot.com/19-promising-php-template-engines   -  person Dominic Rodger    schedule 17.11.2009
comment
Я расширяю механизм шаблонов, встроенный в CodeIgniter, и операторы if — это единственное, что мне нужно.   -  person Christoffer    schedule 17.11.2009


Ответы (3)


\1 будет содержать ваше первое совпадение, поэтому вы можете сделать это:

preg_match_all('|([\t ]?){if (.+?) is (.+?)}(.+?)\1{endif}|s', $template, $match);

Однако это не обязательно будет соответствовать правильному вхождению {endif}, а только следующему вхождению, которому предшествует правильное количество вкладок.

person Rob    schedule 17.11.2009

Обычно вы не можете использовать регулярные выражения для этой проблемы, потому что определенный вами язык не является регулярным (поскольку он требует подсчета вхождений {if} и {endif}).

У вас есть вариант классической проблемы соответствия скобок.

Для отслеживания вхождения {if} и {endif}.

person Dominic Rodger    schedule 17.11.2009

если вы используете явный оператор «endif», ваши блоки уже закрыты, и нет необходимости делать какие-либо специальные отступы, просто сопоставьте '/{if.+?}(.+?){endif}/'.1 Если, с другой стороны, вы используете блоки отступов в стиле Python, вы можете избавиться от {endif} (и скобок) и сопоставлять только уровни отступов

  if condition
      this line is in the if block
      this one too
  this one not

ваше выражение будет таким

 /([\t]+)if(.+)\n((\1[\t]+.+\n)+)/

«условие» будет соответствовать 2, а тело оператора — 3.

1 на самом деле это должно быть что-то вроде /{if}((.(?!{if))+?){endif}/s для правильной обработки вложенных if.

person user187291    schedule 17.11.2009