Регулярное выражение приводит к сбою 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)]

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


person Paul    schedule 31.08.2010    source источник
comment
Я также изучил PECL и Pear HTML_BBCodeParser. Но я не хочу, чтобы мое приложение зависело от расширений — я бы сказал, что этот вариант гораздо предпочтительнее, чем изобретать велосипед.   -  person Jonathan Fingland    schedule 01.09.2010
comment
I like to do things on my own! - почему так? Вы также пишете свой собственный движок регулярных выражений? Или ваш собственный интерпретатор/среда выполнения php?   -  person VolkerK    schedule 01.09.2010
comment
Кстати: вы можете разбить код регулярного выражения на несколько строк и пояснить его части комментариями. Думаю, это повысит ваши шансы на получение помощи.   -  person VolkerK    schedule 01.09.2010
comment
Спасибо за подсказку, VolkerK. Я не имел в виду именно то, что мне нравится делать что-то самостоятельно! Ну ладно.. Давайте забудем об этом. Я объяснил код, надеюсь, теперь все в порядке.   -  person Paul    schedule 01.09.2010
comment
Можете ли вы привести пример строки для каждого ограничения?   -  person Artefacto    schedule 01.09.2010
comment
Артефакт: $txt = '[b]'.str_repeat('a', 338).'[/b]'; 338 символов 'a' внутри тега [b][/b].   -  person Paul    schedule 01.09.2010


Ответы (2)


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

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

http://htmlpurifier.org/

person NullUserException    schedule 31.08.2010
comment
Хм... Возможно, вы правы насчет использования регулярных выражений в таких случаях. Что ж, HTML вместо BBCode было бы здорово, но люди привыкли к BBCode, и теперь это что-то вроде стандарта, так что вы не можете его выбросить. - person Paul; 01.09.2010

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

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

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

Я люблю делать что-то самостоятельно!

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

Мое предложение (и решение) для вас - использовать парсер BBCode.

ИЗМЕНИТЬ

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

person Vivin Paliath    schedule 31.08.2010
comment
Ну, я говорил о расширениях на стороне сервера (я имею в виду, что они должны быть установлены хостинговой компанией или администратором сервера), которые предлагает php.net. Всегда лучше иметь отдельное приложение, которое можно просто загрузить на хост и оно готово к использованию. - person Paul; 01.09.2010
comment
Это должен быть комментарий, поскольку он не отвечает на вопрос OP. - person Artefacto; 01.09.2010
comment
Я думаю, вы пропустили эту часть: мое предложение (и решение) для вас - использовать парсер BBCode и часть после редактирования. - person Vivin Paliath; 01.09.2010
comment
@Paul, вы всегда можете попросить хостинговую компанию или администратора сервера включить это конкретное расширение. Существует множество удобных для разработчиков хостинг-решений. Если бы это было не так, вам пришлось бы переписывать каждое расширение! - person Vivin Paliath; 01.09.2010