PHP PCRE-корректное поведение вложенных тегов
Я хочу написать symple (состоящий из одного вызова preg_replace) forum parser, и у меня возникают проблемы с вложенными тегами.
Например, если кто-то кого-то цитирует, я не могу добиться правильного поведения.При наличии:
[quote=Tom]
[quote=Jerry]
Lorem
[/quote]
Ipsum
[/quote]
Dolor.
Я хочу что-то вроде этого:
<blockquote>
<p><strong>Tom wrote</strong></p>
<blockquote>
<p><strong>Jerry wrote:</strong></p>
<p>Lorem</p>
</blockquote>
Ipsum
</blockquote>
Dolor.
У меня есть такой код:
preg_replace('~[quote (.+)](.+)[/quote]~is', '<blockquote><p><strong>$1</strong> wrote:</p><p>$2</p></blockquote>', $value);
Эта версия жадная. Если у меня есть два отдельных блока [quote]
, регулярное выражение обертывает весь текст между первым [quote]
и вторым [/quote]
.
Если я добавлю модификатор U
, это будет слишком неуместно - первый тег [quote]
сопряжен с первым (вложенным и не относящимся к делу) тегом [/quote]
.
Спасибо за любую помощь!
3 ответа:
Существует пакет PEAR HTML_BBCodeParser , а также PHP имеет собственное расширение для разбора кода, например: http://www.php.net/manual/en/function.bbcode-create.php
Не используйте для этого регулярное выражение. Используйте предоставленное официальное расширение PECL:
Пример (взят из документации):
<?php $arrayBBCode=array( ''=> array('type' => BBCODE_TYPE_ROOT, 'childs' => '!i'), 'i'=> array('type' => BBCODE_TYPE_NOARG, 'open_tag' => '<i>', 'close_tag' => '</i>', 'childs' => 'b'), 'url'=> array('type' => BBCODE_TYPE_OPTARG, 'open_tag' => '<a href="{PARAM}">', 'close_tag' => '</a>', 'default_arg' => '{CONTENT}', 'childs' => 'b,i'), 'img'=> array('type' => BBCODE_TYPE_NOARG, 'open_tag' => '<img src="', 'close_tag' => '" />', 'childs' => ''), 'b'=> array('type'=>BBCODE_TYPE_NOARG, 'open_tag' => '<b>', 'close_tag' => '</b>'), ); $text = <<<EOF [b]Bold Text[/b] [i]Italic Text[/i] [url]http://www.php.net/[/url] [url=http://pecl.php.net/][b]Content Text[/b][/url] [img]http://static.php.net/www.php.net/images/php.gif[/img] [url=http://www.php.net/] [img]http://static.php.net/www.php.net/images/php.gif[/img] [/url] EOF; $BBHandler = bbcode_create($arrayBBCode); echo bbcode_parse($BBHandler, $text); ?>
С помощью некоторых рекурсивных регулярных выражений:
function replace_quotes_callback($matches) { $cite = empty($matches[1]) ? '' : '<p><strong>' . $matches[1] . '</strong> wrote:</p>'; return '<blockquote>' . $cite . '<p>' . replace_quotes($matches[2]) . '</p></blockquote>'; } function replace_quotes($data) { return preg_replace_callback('~\[quote(?:=([^\]]+))?\]((?:(?R)|.)*?)\[/quote\]~s', 'replace_quotes_callback', $data); }
Шаблон соответствует только внешним блокам цитат, а функция обратного вызова
replace_quotes_callback
заменяет кавычки внутри себя рекурсивным вызовомreplace_quotes
.