Я думаю, что лучшим способом решения этой проблемы было бы сделать это в несколько разных шагов.
Во-первых, вы должны использовать preg_replace_callback с /(?>{([^}]+)})(.*)?{\/\1}/sim
в качестве регулярного выражения.Это найдет верхний уровень {tag} {/ tag}.$ Match [2] будет содержать содержимое (без тегов), а $ match 1 будет содержать сам тег.
Вы должны создать функцию, которая вызывается рекурсивно, чтобы в обратном вызове, он вызывается снова в $ match [2], так что найдите потомки {теги} на случай, если их будет больше.Вот как вы пройдете по дереву.
Наконец, вы должны создать третью функцию, которая обрабатывает {% tag%}.Я бы снова использовал preg_replace_callback и использовал бы оператор switch для обработки имени тега.
Это должно указать вам правильное направление.
РЕДАКТИРОВАТЬ: Вот полностью функциональная демонстрацияиз того, что я описал выше: \
<?php
$content = <<<END
{a}
{b}I like {%first%} {%last%} a {c}lot{/c}.{/b}
{/a}
END;
echo find_tags($content);
function find_tags($content)
{
return preg_replace_callback('/(?>{([^}]+)})(.*)?{\/\1}/sim', 'find_tags_callback', $content);
}
function find_tags_callback($matches)
{
// Find and process any children tag pairs.
$matches[2] = find_tags($matches[2]);
// Process the tags {%tag%}.
$matches[2] = preg_replace_callback('/{%([^%]+)%}/sim', 'process_tags', $matches[2]);
switch ( $matches[1] )
{
case 'a':
$tag = 'div';
break;
case 'b':
$tag = 'p';
break;
case 'c':
$tag = 'b';
break;
}
return '<'.$tag.'>'.$matches[2].'</'.$tag.'>';
}
function process_tags($matches)
{
switch ( $matches[1] )
{
case 'first':
return 'Francois';
break;
case 'last':
return 'Deschenes';
break;
}
}
//
Результирующая строка будет: <div><p>I like Francois Deschenes a <b>lot</b>.</p></div>
.