PHP: Как мне удалить вложенные теги и переместить их без вложенного способа?

Мне нужно удалить все вхождения тега стиля BB из строки. Теги могут быть вложенными, и я терплю неудачу. Мне также нужно переместить каждый тег и содержимое в конец строки и заменить тег элементом HTML. Я пытался поиграть с regex и preg_replace_callback, но пока что безуспешно. Я также попытался изменить следующее, но также не повезло: удаление вложенного bbcode (кавычек) в PHP и как я могу удалить элемент html и его содержимое с помощью RegEx. Я не думаю, что могу использовать такой синтаксический анализатор HTML, потому что HTML-код искажен (дочерние элементы в элементах, которые не могут иметь дочерних элементов).

Вот как выглядит строка:

This is some 
[tag] attribute=1 attribute2=1 
     [tag] attribute=1 attribute2=1 [/tag] 
     [tag] attribute=1 attribute2=1 [/tag]
[/tag]
 text.

Результат должен выглядеть так:

This is some text.
<br attribute=1 attribute2=1>
<br attribute=1 attribute2=1>
<br attribute=1 attribute2=1>

Любая помощь будет оценена.

1 ответ

Решение

Уличная репутация: я работал на Infopop (позже известный как Groupee, теперь Social Strata), создателей UBBCode, вещи, которая была скопирована и преобразована в просто старый обычный "BBCode".

tl;dr: время написать собственный синтаксический анализатор без регулярных выражений.


Большинство анализаторов BBCode используют регулярные выражения, и это работает в большинстве случаев, но здесь вы делаете что-то свое. Простые старые регулярные выражения вам не помогут. Регулярные выражения имеют два режима работы, которые мешают нам: мы можем либо сопоставить все между двумя тегами в "жадном" режиме, либо в "не жадном" режиме.

В "жадном" режиме мы будем фиксировать все между самой первой задачей открытия и самой последней закрывающей меткой. Это ужасно ломает вещи. Возьми этот случай:

[a][b][c]...[/c][/b][/a]...[a]...[/a]

Жадное регулярное выражение как \[a\].+\[/a\] собирается захватить все, начиная с первого открывающего тега и заканчивая последним закрывающим тегом, игнорируя тот факт, что средство закрытия не закрывает открывающий элемент.

Другой вариант хуже. Возьми этот случай:

[a][b][a]...[/a][/b][/a]

Нечестивое регулярное выражение, как \[a\].+?\[/a\] (единственное изменение - знак вопроса) будет соответствовать первому открывающему тегу, но затем он будет соответствовать первому закрывающему тегу, снова игнорируя, что закрывающий тег не принадлежит открывающему тегу.

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

В тот момент, когда вы разрешаете вложение одинаковых меток, слепая грубая сила больше не является подходящим инструментом.

Если ни один из механизмов разбора BBCode там не будет работать для вас, вам, возможно, придется написать свой собственный. Проверьте их все. Есть некоторые на PEAR, есть расширение PECL и т. Д. Также проверьте другие языки для вдохновения, CPAN в Perl имеет дюжину различных реализаций, некоторые из которых очень мощные и сложные (если в этом миксе нет подходящего синтаксического анализатора рекурсивного спуска Буду в депрессии). Это хороший вызов, но это не слишком сложно. С другой стороны, я написал сейчас пять (ни один из которых я не могу выпустить), так что, может быть, я предвзятый?

Начните с взрыва строки на [ а также ], Просмотрите полученный массив, отслеживая, когда индекс массива после открывающей скобки и до следующей закрывающей скобки выглядит как действительный тег и / или атрибуты. Вам нужно будет подумать о том, что происходит, когда атрибут может содержать скобки, или, что еще хуже, являются URL-адресами со скобками (например, синтаксис PHP-массива). Вам также необходимо подумать об атрибутах в целом, в том числе о том, как (если?) Они заключаются в кавычки, если допустимо несколько атрибутов для каждого тега (как в вашем примере), и что делать с недопустимыми атрибутами.

Продолжая обрабатывать строку, вы также должны будете отслеживать, какие теги открыты и в каком порядке. Вам придется подумать о том, какие теги разрешены внутри других тегов. Вам также придется иметь дело с неправильным вложением, как [a][b][/a][/b], Ваши варианты будут либо повторно открывать внутренний тег после закрытия внешнего, либо закрывать внутренний, как только внешний делает. Хуже того, различное поведение может иметь смысл в зависимости от ситуации. Хуже-хуже, такие дурацкие метки, как [*] внутри [list], который традиционно не имеет закрывающего тега!

После того, как вы обработали строку и создали список открытых и закрывающих тегов (и, возможно, перебалансировали открытия и закрытия), вы можете преобразовать результат в HTML или что-то еще, что в итоге получится. Это когда и как вы будете перемещать вывод этих конкретных тегов в конец нового документа.

Как только вы закончите, напишите тысячу тестов. Попробуйте разбить его, разбить на мелкие кусочки, создать уязвимости XSS и сделать все возможное, чтобы ваша жизнь стала адом. Это будет стоить того, потому что результатом будет механизм BBCode, который будет делать то, что вы пытаетесь сделать.

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