#php #regex #preg-match
#php #регулярное выражение #preg-match
Вопрос:
я использую этот шаблон '/({(w )}(.*))?{%(w )%}((.*){/(w )})?/i'
для извлечения тегов из шаблона с помощью preg_match
функции.
пример шаблона:
<table id="middle" cellspacing="0px" cellpadding="0px">
{middle}
<tr>
{left}<td>{%left%}</td>{/left}
<td>{%middle%}{%content%}</td>
{right}<td>{%right%}</td>{/right}
</tr>
{/middle}
</table>
как убедиться, что start
и end
каждого тега действительно соответствуют его имени
в этом примере middle
тег совпадает для обоих middle
и content
, хотя он должен просто соответствовать middle
тегу
Ответ №1:
Я думаю, что лучшим способом решить эту проблему было бы сделать это в несколько разных шагов.
Во-первых, вы должны использовать preg_replace_callback с /(?>{([^}] )})(.*)?{/1}/sim
в качестве регулярного выражения. Это позволит найти {тег} верхнего уровня{/tag}. $matches[2] будет содержать содержимое (без тегов), в то время как $matches1 будет содержать сам тег.
Вы должны создать функцию, которая вызывается рекурсивно, чтобы при обратном вызове она вызывалась снова для $ matches [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>
.
Ответ №2:
1 Я уверен, но не уверен, что для того, чтобы убедиться, что входящие теги ({this}{/this}) соответствуют тегам данных ({%this%}), вам понадобится сопровождающий оператор if для проверки возвращаемых строк.
Я бы использовал функцию preg_replace_callback, например:
<?php
$str = '<template contents>';
$newstr = preg_replace_callback(
'/({(w )}(.*))?{%(w )%}((.*){/(w )})?/i',
'check', //<-- the function to send matches to
$str);
function check($matches){
if($matches[1] == $matches[2] amp;amp; $matches[1] == $matches[3]){
/*Do Work*/
return ''; //new formatted string to send back to the $newstr var
}
}
?>
функция preg_replace_callback отправляет все найденные соответствия в виде массива указанной функции для обработки, затем вы возвращаете новую форматированную строку из этой функции.
Комментарии:
1. вам не нужен оператор if. Выполнение этого таким образом на самом деле приведет ко многим недопустимым совпадениям, особенно: {a}{b}{/b}{/a} приведет к {a}{/b}. Вам нужно посмотреть на обратные ссылки регулярного выражения . Смотрите мой пример. Это решение также не будет работать, если теги находятся в нескольких строках.