PHP - мне нужна помощь с моим Regex - PullRequest
0 голосов
/ 23 июня 2010

Я создал простой шаблон «движок» в PHP для замены сгенерированных PHP данных на HTML-страницу. Вот как это работает:

В моем основном файле шаблона у меня есть переменные, такие как:

<title><!-- %{title}% --></title>

Затем я назначаю данные в эти переменные для загрузки главной страницы

$assign = array (
  'title' => 'my website - '
);

У меня есть отдельные блоки шаблонов, которые загружаются для страниц контента. Вышесказанное действительно обрабатывает верхний и нижний колонтитулы. В одном из этих «файлов шаблонов контента» у меня есть переменные вроде:

<!-- %{title=content page}% -->

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

<title>my website - content page</title>

Это делается с помощью следующего кода:

if (preg_match('/<!-- %{title=\s*(.*?)}% -->/s', $string, $matches)) {
   // Find variable names in the form of %{varName=new data to append}%
   // If found, append that new data to the exisiting data
   $string       = preg_replace('/<!-- %{title=\s*(.*?)}% -->/s', null, $string);
   $varData[$i] .= $matches[1];
}

Это в основном удаляет переменные шаблона и затем присваивает данные переменной существующей переменной. Теперь все это прекрасно работает. У меня проблемы с вложением шаблонных переменных. Если я сделаю что-то вроде:

<!-- %{title=content page (author: <!-- %{name}% -->) -->

Временами шаблон путает открывающий и закрывающий теги каждой переменной.

Как я могу исправить свое регулярное выражение, чтобы предотвратить это?

Спасибо.

Ответы [ 6 ]

4 голосов
/ 23 июня 2010

Ответ: вы не делаете это с помощью регулярных выражений. Регулярные выражения являются регулярным языком. Когда вы начинаете вкладывать вещи, это уже не обычный язык. Это, как минимум, контекстно-свободный язык («КЛЛ»). КЛЛ могут обрабатываться только (если они однозначны) со стеком.

В частности, обычные языки могут быть представлены с помощью конечного автомата ("FSM"). Для КЛЛ требуется автомат («КПК»).

Примером разницы являются вложенные теги в HTML:

<div>
  <div>inner</div>
</div>

Мой совет: не пишите свой собственный язык шаблонов. Это было сделано. Много раз. Используйте Smarty или что-то в Zend, Kohana или что-то еще. Если вы пишете свои собственные, делайте это правильно. Разобрать его.

1 голос
/ 23 июня 2010

Почему вы катите свой собственный шаблонизатор? Если вы хотите такого рода сложности, есть много мест, которые уже нашли решения для этого. Вы должны просто подключить Smarty или что-то в этом роде.

0 голосов
/ 23 июня 2010

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

Если вместо этого вы ищете справа налево для открывающего тега, <!-- %{ в вашем синтаксисе, используя strrpos (PHP5 +), то ищите вперед первое вхождение следующего закрывающего тега, а затем сначала замените этот блок, в итоге вы в первую очередь замените самые вложенные переменные. Это должно решить вашу проблему.

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

0 голосов
/ 23 июня 2010

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

В вашем случае это, вероятно, выглядело бы так:

/(<!--([^(-->)]*?)-->)/

Подобные регулярные выражения - страшный сон для объяснения, но в основном ([^(-->)]*) найдет любую строку, которая не включаетваш закрывающий тег (назовем это AAA).Он будет внутри подходящей группы, которая сама является вашим тегом шаблона, (<!--AAA-->).

Я убежден, что этот вид шаблонного метода - неправильный способ делать вещи, но я никогда не знал достаточно, чтобы сделать это лучше.Меня всегда беспокоило в ASP и ColdFusion, что вам приходилось вкладывать свои теги сценариев в HTML, и когда я сам начал делать это, я считал это личной ошибкой.

Большинство регулярных выражений, которые я сейчас делаю, написаны на JavaScript,Возможно, мне не хватает некоторых удивительных нюансов, которые PHP имеет через Perl.Я был бы счастлив, если бы кто-то мог написать это более аккуратно.

0 голосов
/ 23 июня 2010

Чтобы решить вашу проблему, вы должны

  • заменить preg_match() на preg_match_all();
  • найти шаблон и заменить его с последнего на первый;
  • используйте более строгий шаблон, такой как '/<!-- %{title=\s*([^}]*?)}% -->/s'.
0 голосов
/ 23 июня 2010

Если вы спрашиваете, что я думаю, вы спрашиваете, это буквально невозможно. Если я правильно прочитал ваш вопрос, вы хотите сопоставить произвольно вложенные последовательности <!-- ... --> с конкретными элементами внутри. К сожалению, регулярные выражения могут соответствовать только определенным классам строк; любое регулярное выражение может соответствовать только регулярному языку . Один из известных языков, который не регулярный, - это язык сбалансированных скобок (также известный как язык Дейка) , который именно то, что вы пытаетесь сопоставить. Чтобы соответствовать произвольно вложенным строкам комментариев, вам нужен более мощный инструмент. Я вполне уверен, что существуют уже существующие механизмы шаблонов PHP; Вы можете посмотреть на один из них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...