Как преобразовать URL-тег bbcode в гиперссылку html, используя значения тега bbcode? - PullRequest
0 голосов
/ 06 мая 2018

Как преобразовать тег bbcode [url] в тег <a> с атрибутом href и текстом между открывающим и закрывающим тегом?

Вот несколько примеров строк:

[url]https://any.com/any[/url]

[URL="https://any.com/any?any=333"]text text[/URL]

[url]http://www.any.com/any?any=44#sss[/url]

* Обратите внимание, что подстрока в двойных кавычках в открывающем теге [url] является необязательной и влияет на желаемый результат ...

Я пробовал этот шаблон:

(?:\[url="(https?://(?:www)?.+?)\]|\[url\](https?://(?:www)?.+\[)) 
\[url="(https?:\/\/(?:www\.)?.+?)\]|\[url\](https?:\/\/(?:www\.)?.+)\[\/url\]
\[url="(https?:\/\/(?:www\.)?.+)"\]|\[url\](https?:\/\/(?:www\.)?.+)\[\/url\]

с чем-то вроде:

$pattern ='##i';
$text = preg_replace($pattern,'',$text);

Мой желаемый результат из приведенных выше тегов bbcode url должен быть:

<a href="https://any.com/any">https://any.com/any</a>

<a href="https://any.com/any?any=333">text text</a>

<a href="http://www.any.com/any?any=44#sss">http://www.any.com/any?any=44#sss</a>

Другими словами, если url находится в двойных кавычках открывающего тега [url], используйте это значение в качестве значения href и сохраните innerHTML тега [url] в качестве innerHTML сгенерированного <a> тег.

Если URL-адрес находится не в двойных кавычках, а между открывающим и закрывающим тегами [url], используйте это значение как значение href и как innerHTML для <a>.

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

ОБНОВЛЕНИЕ: прокомментированное решение Казимира является более прямым / чистым.

Код: ( Демо ) ( Шаблон Демо )

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]
)
0 голосов
/ 06 мая 2018

Вы можете использовать

(?i)\[url(?|="(?P<url>[^"]+)|\](?P<url>[^][]+))

См. демонстрацию на regex101.com .


Разбит:
(?i)                   # case insensitive
\[url                  # [url
(?|                    # branch reset
    ="(?P<url>[^"]+)   # either ="..."
    |                  # or
    \](?P<url>[^][]+)  # ]...[/url]
)

В любом случае вам понадобится группа "url".

...