Регулярное выражение завершает работу Apache из-за ограничений PCRE

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

Дело в том, что я столкнулся с проблемой, подобной этой: Apache / PHP в Windows вылетает с регулярным выражением

Это означает, что если я сделаю что-то похожее на приведенный ниже пример, Apache аварийно завершит работу из-за того, что количество рекурсий достигло 690 (ограничение памяти 1 МБ для PCRE)

$txt = '[b]'.str_repeat('a', 338).'[/b]';  // if I change repeat count to lower value it's ok
$regex = '#\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))](?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)\[/(?P=tag)]#mi';

echo preg_replace_callback($regex, function($matches) { return $matches['content']; }, $txt);

Поэтому мне нужно как-то свести к минимуму необходимость * а также + в моем регулярном выражении, но это то, где у меня нет идей, поэтому я подумал, что вы могли бы что-то предложить.

Другие подходы для разбора bbcode (который может обрабатывать вложенные теги) приветствуются. Однако я не хотел бы использовать уже построенный класс или что-то. Мне нравится делать вещи самостоятельно!

Я также посмотрел в PECL и Pear HTML_BBCodeParser. Но я не хочу, чтобы мое приложение зависело от расширений. Скорее всего, я могу сделать какой-нибудь скрипт, который проверяет это расширение и, если он не существует, использовать парсер BBCode, который я пытаюсь сделать здесь.

Извините, если мои описания мрачны, я не профессионал в английском ^^

РЕДАКТИРОВАТЬ. Итак, регулярное выражение объяснило:

\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))]

Это мой вводный тег. Я использовал именованные группы. С помощью "тега" я идентифицирую тег, а с "атрибутами" - атрибуты тегов. Думайте о теге как об атрибуте. Так что здесь происходит? Я пытаюсь соответствовать тегу, когда тег совпадает, я пытаюсь соответствовать чему-либо после = знак или что-нибудь после \s (проставка), пока не достигнет закрытия тега ],

(?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)

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

\[/(?P=tag)]

... конечный тег найден.

2 ответа

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

На самом деле, я думаю, что BBCode - это зло. BBCode - это язык разметки, изобретенный ленивыми программистами, которые не хотят правильно фильтровать HTML. В результате у нас теперь есть свободный "стандарт", который сложно реализовать. Отфильтруйте ваш HTML правильно:

http://htmlpurifier.org/

Я собирался предложить BBCodeParser...

Я также посмотрел в PECL и Pear HTML_BBCodeParser. Но я не хочу, чтобы мое приложение зависело от расширений

Я нахожу это очень странным. Зачем изобретать велосипед? Одним из принципов хорошей программной инженерии является СУХОЙ (не повторяй себя). Вы пытаетесь решить проблему, которая уже была решена.

Мне нравится делать вещи самостоятельно!

Это само по себе неплохо, но бывают случаи, когда вам лучше использовать проверенное и верное решение; тот, который лучше протестирован и более надежен, чем ваш (как вы выяснили). Таким образом, вы потратите время на проблему, которую вы действительно хотите решить, вместо того, чтобы решить проблему, которая уже была решена. Не попадайтесь в ловушку изобретения колеса.:)

Мое предложение (и решение) для вас состоит в том, чтобы использовать парсер BBCode.

РЕДАКТИРОВАТЬ

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

Другие вопросы по тегам