Как уловить вложенные {% if …%} {% endif%} статусы с регулярным выражением

Это то, что я получил сейчас:

/{% if(.+?) %}(.*?){% endif %}/gusi

Он ловит несколько операторов if и т. Д.

IMG: http://img.ruphp.com/php/2015-02-07_23-22-11.png

Но когда я делаю вложенные, так что если в if, то останавливается при первом появлении {% endif%}

IMG: http://img.ruphp.com/php/2015-02-08_09-29-43.png

Есть ли способ уловить как можно больше {% endif%} операторов, чем есть {% if …%}, и если да, то как?

Related of "Как уловить вложенные {% if …%} {% endif%} статусы с регулярным выражением"

Не используйте regexen, используйте существующий анализатор Twig. Вот пример экстрактора, который я написал, который анализирует пользовательские теги и извлекает их: https://github.com/deceze/Twig-extensions/tree/master/lib/Twig/Extensions/Extension/Gettext

Задача лексера – превратить исходный код Twig в объекты; вы можете расширить его, если вам нужно подключиться к этому процессу:

 class My_Twig_Lexer extends Twig_Lexer { ... /** * Overrides lexComment by saving comment tokens into $this->commentTokens * instead of just ignoring them. */ protected function lexComment() { if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); } $value = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); $token = new Twig_Extensions_Extension_Gettext_Token(Twig_Extensions_Extension_Gettext_Token::COMMENT, $value, $this->lineno); $this->commentTokens[] = $token; $this->moveCursor($value . $match[0][0]); } ... } 

Как правило, узлы комментариев Twig отбрасываются Twig, этот лексер сохраняет их.

Однако ваша главная задача будет заключаться в работе с парсером:

 $twig = new Twig_Environment(new Twig_Loader_String); $lexer = new My_Twig_Lexer($twig); $parser = new Twig_Parser($twig); $source = file_get_contents($file); $tokens = $lexer->tokenize($source); $node = $parser->parse($tokens); processNode($node); 

$node – это корневой узел дерева узлов, которые представляют источник Twig объектно-ориентированным способом, все правильно проанализированы. Вам просто нужно обработать это дерево, не беспокоясь о точном синтаксисе, который использовался для его создания:

  processNode(Twig_NodeInterface $node) { switch (true) { case $node instanceof Twig_Node_Expression_Function : processFunctionNode($node); break; case $node instanceof Twig_Node_Expression_Filter : processFilterNode($node); break; } foreach ($node as $child) { if ($child instanceof Twig_NodeInterface) { processNode($child); } } } 

Просто переходите его, пока не найдете тот узел, который вы ищете, и получите его информацию. Поиграйте с ним немного. Этот примерный код может быть или не быть устаревшим, вам придется вникнуть в исходный код парсера Twig, чтобы понять его.

Практически тривиально изменить шаблон в рекурсивный шаблон :

 {% if(.+?) %}((?>(?R)|.)*?){% endif %} 

Рабочий пример: https://regex101.com/r/gX8rM0/1

Однако это было бы плохой идеей: в шаблоне отсутствует много случаев, которые на самом деле являются ошибками в вашем парсере. Всего несколько примеров:

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

     {% if aaa %} 123 <!-- {% endif %} --> {% endif %} 
  • Строковые литералы :

     {% if aaa %}a = "{% endif %}"{% endif %} {% if $x == "{% %}" %}...{% endif %} 
  • Экранированные символы (вам нужны экранированные символы, не так ли?):

     <p>To start a condition, use <code>\{% if aaa %}</code></p> 
  • Недопустимый ввод :
    Было бы неплохо, если бы парсер мог неплохо работать на недопустимом вводе и указывать на правильное положение ошибки.