регулярное выражение bbcode и гиперссылка из строки

[url=http://stackoverflow.com]stackoverflow[/url]
[url=http://stackoverflow.com]http://stackoverflow.com[/url]
http://stackoverflow.com
[url=http://stackoverflow.com][img]url_to_img[/img][/url]
[url=http://stackoverflow.com][b]stackoverflow[/b][/url]
[url=http://stackoverflow.com][b][u][i]stackoverflow[/i][/u][/b][/url]
[url=http://stackoverflow.com][color=red]stackoverflow[/color][/url]
[url=http://stackoverflow.com][h1][color=red]stackoverflow[/color][/h1][/url]

Измените его на это:

<a href="http://stackoverflow.com">stackoverflow</a>
<a href="http://stackoverflow.com">http://stackoverflow.com</a>
<a href="http://stackoverflow.com">http://stackoverflow.com</a>
<a href="http://stackoverflow.com"><img src="url_to_img" /></a>
<a href="http://stackoverflow.com"><strong>stackoverflow</strong></a>
<a href="http://stackoverflow.com"><span style="color:red">stackoverflow</span></a>
<a href="http://stackoverflow.com"><h1><span style="color:red">stackoverflow</span></h1></a>

Я попытался найти что-то, что заменит все URL-адреса, а не bbcode.
Я попытался использовать https://github.com/wookieb/bbcode, но когда я обновляю php 5.2 до 5.5, перестаю работать.
Я пробовал использовать http://jbbcode.com/, но не анализировать URL из строки.


person Pionas    schedule 25.08.2015    source источник


Ответы (1)


Я перестроил все, кроме одной строки, только с URL-адресом.

<?php
$input = "[url=http://stackoverflow.com]stackoverflow[/url]
[url=http://stackoverflow.com]http://stackoverflow.com/damn[/url]
http://stackoverflow.com/ok
[url=http://stackoverflow.com][img]url_to_img[/img][/url]
[url=http://stackoverflow.com][b]stackoverflow[/b][/url]
[url=http://stackoverflow.com][b][u][i]stackoverflow[/i][/u][/b][/url]
[url=http://stackoverflow.com][color=red]stackoverflow[/color][/url]
[url=http://stackoverflow.com][h1][color=red]stackoverflow[/color][/h1][/url]";

$match = [
    '/\[url=([^\]]+)\](.*)\[\/url\]/im',
    '/\[img\](.*)\[\/img\]/im',
    '/\[b\](.*)\[\/b\]/im',
    '/\[u\](.*)\[\/u\]/im',
    '/\[i\](.*)\[\/i\]/im',
    '/\[color=([^\]]+)\](.*)\[\/color\]/im',
    '/\[h([1-6])\](.*)\[\/h(?:[1-6])\]/im',
];
$replace = [
    '<a href="$1">$2</a>',
    '<img src="$1">',
    '<strong>$1</strong>',
    '<u>$1</u>',
    '<em>$1</em>',
    '<span style="color:$1;">$2</span>',
    '<h$1>$2</h$1>',
];

echo preg_replace($match, $replace, $input);

Это дает следующий результат:

<a href="http://stackoverflow.com">stackoverflow</a>
<a href="http://stackoverflow.com">http://stackoverflow.com/damn</a>
http://stackoverflow.com/ok
<a href="http://stackoverflow.com"><img src="url_to_img"></a>
<a href="http://stackoverflow.com"><strong>stackoverflow</strong></a>
<a href="http://stackoverflow.com"><strong><u><em>stackoverflow</em></u></strong></a>
<a href="http://stackoverflow.com"><span style="color:red;">stackoverflow</span></a>
<a href="http://stackoverflow.com"><h1><span style="color:red;">stackoverflow</span></h1></a>

Тот, который соответствует только URL-адресу, немного сложнее. Это зависит от того, насколько продвинутым вы хотите его сделать. Он может обнаруживать простые вещи, такие как example.com, или более сложные вещи, такие как ☃.net (что приводит к http://xn--n3h.net/)

Некоторое объяснение
Первое правило, которое мы пытаемся сопоставить и заменить, — это код URL. Мы просто начинаем с поиска внешнего вида [url=, простого и жестко закодированного. То, что мы ищем дальше, может быть многими вещами, но одно мы знаем точно, что мы должны закончить на ]. Затем мы можем использовать регулярное выражение, которое говорит: match all but ] ([^\]]+) Обратите внимание, что я экранировал символ ], иначе совпадение не удастся.
Затем я снова ищу все ((.*)), пока не достигну жестко заданного ожидаемого значения, [/url].
Это почти полное правило соответствия для каждого типа bbcode, который вы хотели.

Что касается части замены, вы включаете то, чем они должны быть заменены, просто. Чтобы добавить значения, соответствующие регулярному выражению, используйте $1, $2, ..., $n. Соответствие определяется моими круглыми скобками.
Например: '/[url=([^]]+)](.*)[/url] /im'
Сегменты в скобках, выделенные полужирным шрифтом, — это сегменты, содержащие значения, которые мы будем получать из $1и $2.

Я изо всех сил старался объяснить, как это работает. Если что-то осталось непонятным, укажите на это, и я постараюсь объяснить подробнее

person Morten    schedule 25.08.2015
comment
Я проголосовал, но вы должны объяснить свой код OP - person Robert; 26.08.2015
comment
Спасибо за голосование. Добавил некоторые пояснения внизу, или, по крайней мере, я попытался объяснить некоторые части как можно лучше. Если у вас есть предложения, что еще объяснить или как объяснить это по-другому, пожалуйста, дайте мне знать. @Роберт - person Morten; 26.08.2015
comment
Конечно, вы не должны использовать жадные операторы, замените .* на .*?, если вы знаете, почему, тогда добавьте два одинаковых bbcode в свой текст и посмотрите, что произойдет :) - person Robert; 26.08.2015
comment
Были в такой ситуации раньше. Друг работал с созданным на заказ форумом и хотел поставить тег [quote]. Проблема с .*? в том, что у него первая концовка, а .* последняя. Однако я не помню, что я сделал с несколькими внутри в верхней части головы, но я думаю, что использовал рекурсивную функцию, чтобы перебрать и заменить их все. @Роберт - person Morten; 26.08.2015
comment
Спасибо за работу, хорошо. Но что произойдет, когда я добавлю что-то вроде этого: [url=http://stackoverflow.com][b][u][i]stackoverflow[/i][/b][/u][/url] изменить на: <a href="http://stackoverflow.com"><b><u><i>stackoverflow</i></b></u></a> или [url=http://stackoverflow.com][b][u][i]stackoverflow[/i][/u][/url] изменить на: <a href="http://stackoverflow.com">[b]<u><i>stackoverflow</i></u></a> или что произошло для этого примера: first paragraph... [h1]some title secong paragraph [h1]some title[/h1] - person Pionas; 26.08.2015
comment
Для двух первых примеров здесь вывод будет таким, как вы написали, если вы сделаете небольшую настройку, упомянутую Робертом. Изменив (.*) на (.*?), вы получите именно то, что вы предсказываете. Что касается [h1]..[h1]..[/h1], то он станет‹h1›..[h1]..‹/h1›. Однако, установив для него значение (.*?) вместо (.*), вы получите такой код: [b][i] что-то [/b][/i] правильное редактирование, в то время как правильный путь [b][i] что-то [/ i][/b]. Другими словами, используя (.*), он изменит только действительные данные, в то время как (.*?) изменит, если он найдет совпадение с некоторыми, даже если другой тег не закончился внутри и т. д. @Pionas - person Morten; 26.08.2015