Создание обработчика шаблонов в PHP (проблема с отрицательным взглядом вперед)

Я занимаюсь разработкой небольшого обработчика шаблонов в PHP, например, smarty, гораздо более простого. Я использовал умный раньше, но это было слишком крепким для меня. Я думал, что я готов с моим, но действительно раздражающая ошибка обнаружилась. Моя концепция проста. Я использую preg_split для разделения команд шаблона и HTML-кода, обработки и взрыва. команда {foreach} работает очень хорошо, поэтому я не буду об этом упоминать, ошибка появляется в предложении {if}. "{If} часть" регулярного выражения:

{if\s+[a-zA-Z0-9\{'\}\=\s\/$\!\=]{1,}\s*}

Проблема в том, что я должен разрешить фигурные скобки из-за подстановки переменных, и это заставляет регулярное выражение не останавливаться в конце "{if **}". Я пытался смотреть в будущее с негативным прогнозом и отвергать прогноз с позитивным прогнозом, чтобы исключить "{если", чтобы избежать проблемы, но мне не повезло.

Пример для шаблона:

{if '{$a}' = 'a'}
    blabla
    {if 'c' = 'c'}
        blabla
    {/if}
{/if}
valami más
{if 'b' != 'b'}
    blabla
{/if}
{if '{$c}' = '{$c}'}
    blabla
{/if}

Ожидаемый выход:

{if '{$a}' = 'a'}
{if 'c' = 'c'}
{if 'b' != 'b'}
{if '{$c}' = '{$c}'}

Может ли кто-нибудь помочь, пожалуйста?

1 ответ

Основываясь на вашем описании выше, я создал следующее регулярное выражение. Я надеюсь, что это то, что вы ищете.

<?php

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
    blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
EOD;

$pattern = "~{if\s+'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'\\}~";

preg_match_all($pattern, $string, $matches);

echo '<pre>'.print_r($matches,1).'</pre>';

?>

Выходы:

Array
(
    [0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
    )

)

Обновленный ответ

Имея в виду комментарии ниже, я создал следующее регулярное выражение. Я признаю, что это далеко не лучшее решение, но оно работает, чтобы учесть такие аргументы, как {if '{$c}' = '{$c}' && '{$b}' = '{$b}'}, Вы можете просто продублировать шаблон, чтобы можно было использовать более двух выражений в одном if заявление. Очевидно, это тогда вырастет до нелепой длины! Однако, если это для шаблонного движка, возможно, ему не понадобится много расширяться? Любые другие необходимые операторы также могут быть просто добавлены в регулярное выражение в соответствующем месте.

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

$pattern = "~{if\s+(?:(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))')(?:(?:\s+(?:&&|\\|\\|)\s+)(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'))?)\\}~";

Проверено на:

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
{if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
EOD;

Результат:

Array
(
[0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
        [4] => {if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
    )
)
Другие вопросы по тегам