Доброго время суток. При разработке своего "легковесного" шаблонизатора, ал-я CMF MODx, столкнулся с проблемой вложенности конструкций.
То, что скармливаем (упрощённая для восприятия конструкция):
[[SNIPPET_1
:if
&is=`var`
&then=`[[$CHUNK_1
:if
&is=`var`
&then=`[[SNIPPET_2
:filter
&name=`var`
]]`
]]`
&else=`[[CHUNK_2:upper]]`
:filter
&name=`var`
]]
:if, :filter – фильтры (модификаторы), а &is, &name… - переменные фильтров. Переменные фильтров (&is=var), как можно догадаться должны содержать всё что угодно: от простой строки до html-кода приправленного переменными шаблона (сниппетами, чанками и т.д.)
Проблема заключается в том, как закрыть в данном случае [[SNIPPET_1]], при наличии в нём других переменных шаблона. Стоить заметить, что [[SNIPPET_1]] имеет два применённых к нему фильтра: :if и :filter. Это тоже необходимо учитывать.
Было бы чудесно распарсить данную конструкцию, КАК ЕСТЬ (т.е. учитывать и перевод строки – удобство восприятия)
Собственно, regexp pattern, который применён в проекте:
preg_replace_callback(
'/\[{2}([\$\*\@\%\~]?|\+{1,2})([\w-\.]+)\s*((?:\:[\w]+\s*(?:\s*\&[\w]*\=`(?:.[^\n]*)`)*\s*)*)\s*\]{2}/iu',
function ($call) { },
$subject
)
Выделяет отдельно название переменной шаблона (SNIPPET_1, CHUNK_1, SNIPPET_2…), его тип ("" - сниппет, "$" - чанк, "~" - ссылка…) и фильтры с их содержимым (:if&is=var&then=[[$CHUNK_1]] :filter&name=var). В данном случае, [^\n] является заглушкой, т.е. содержимое переменной фильтра пишется в одну строку без переходов на следующую, чтобы определяет конец переменной фильтра, а именно: &then=[[$CHUNK_1:if&is=var&then=[[SNIPPET_2:filter&name=var]]]] Согласитесь, не очень читабельно получается. Далее парсится в массив конструкция фильтров. Определяется имя фильтра (if, filter…) и переменные каждого фильтра. Regxp pattern:
preg_match_all('/\:([\w]*)((?:\s*\&[\w]*\=`(?:.[^\n]*|)`\s*)*)/iu', $call[3], $found);
И в заключении, цикличный пробег по каждому из фильтров и выполнение функции (соответствует названию фильтра). Для примера приведу функцию фильтра :if :
preg_match_all('/\&([\w]*)\=\`((?:.[^\&]*)?(?(?=:).*?\`\]\](?:.[^&]*)?|(?:.[^\&\:])?))\`/iu', $subject, $found);
Резюмируя: Уважаемые Гуру регулярных выражений, поделитесь опытом, как закрыть конструкцию при наличии в ней вложенности аналогичных конструкций.
RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.
Все вопросы, добавленные на сайт ответов Google, мы скопировали и сохранили здесь. Имена старых пользователей также отображены в том виде, в котором они существовали ранее. Только нужно заново пройти регистрацию, чтобы иметь возможность задавать вопросы, или отвечать другим.
Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.