ОБНОВЛЕНИЕ: прокомментированное решение Казимира является более прямым / чистым.
Код: ( Демо ) ( Шаблон Демо )
echo preg_replace('~\[url(?|]((https?://[^[]+))|(?:="(https?://[^"]+)")](.+?))\[/url]~i', '<a href=\"$1\">$2</a>', $bbcode);
Удвоив захват первой альтернативы в шаблоне, вы можете убедиться, что у вас всегда есть $1
и $2
для применения к замещающей строке.
Вот слегка расширенный вариант шаблона , который рассматривает одинарные кавычки и не цитирует.
(начало предыдущего решения)
Используя preg_match_callback()
, вы можете определить, был ли указан URL внутри открывающего тега [url]
- в этом случае вы захотите сохранить текст, расположенный между открывающим и закрывающим тегами.
Если текст между тегами - это URL, вы используете его в обоих местах в строке тега <a>
.
Неверные строки не будут преобразованы.
Код: ( Демо ) ( Шаблон Демо )
$bbcodes = [
'[URL]www.no.http.example.com[/URL]',
'[url]https://any.com/any[/url]',
'[url="nourl"]nourl[/url]',
'[URL="https://any.com/any?any=333"]text text[/URL]',
'[url="http://www.emptyTEXT.com"][/url]',
'[url]http://www.any.com/any?any=44#sss[/url]',
'[url="https://conflictinglink"]http://differenturl[/url]'
];
foreach ($bbcodes as $bbcode) {
echo preg_replace_callback('~\[url(?:](https?://[^[]+)|(?:="(https?://[^"]+)")](.+?))\[/url]~i',
function($m) {
if (isset($m[2])) {
return "<a href=\"{$m[2]}\">{$m[3]}</a>";
}
return "<a href=\"{$m[1]}\">{$m[1]}</a>";
},
$bbcode);
echo "\n---\n";
}
Выход:
[URL]www.no.http.example.com[/URL]
---
<a href="https://any.com/any">https://any.com/any</a>
---
[url="nourl"]nourl[/url]
---
<a href="https://any.com/any?any=333">text text</a>
---
[url="http://www.emptyTEXT.com"][/url]
---
<a href="http://www.any.com/any?any=44#sss">http://www.any.com/any?any=44#sss</a>
---
<a href="https://conflictinglink">http://differenturl</a>
---
Распределение по шаблону:
~ #start of pattern delimiter
\[url #match literally [url
(?: #start non-capturing group #1
] #match literally ]
(https?://[^[]+) #match and store as Capture Group #1 http , an optional s , colon , two forward slashes, then one or more non-opening square brackets (since valid href values cannot have square brackets)
| #or
(?: #start non-capturing group #2
=" #match literally ="
(https?://[^"]+) #match and store as Capture Group #2 (same logic as Capture Group #1)
" #match literally "
) #end non-capturing group #2
] #match literally ]
(.+?) #match (lazily) and store as Capture Group #3 one or more characters (this is the innerHTML component)
) #end non-capturing group #1
\[/url] #match literally [/url]
~ #end of pattern delimiter
Функция обратного вызова оценивает элементы в массиве match ($m
) и условно генерирует и возвращает желаемый результат. Если есть какие-либо совпадения, вывод будет содержать:
array(
0 => [the fullstring match]
1 => [the url of a bbcode tag that does not have a quoted url]
)
или
array(
0 => [the fullstring match]
1 => '' // <-- empty string
2 => [the quoted url of the bbcode tag]
3 => [the text between the opening an closing bbcode tags]
)