如何使用bbcode标签的值将bbcode url标签转换为html超链接?

时间:2018-05-06 08:05:44

标签: php regex hyperlink preg-replace bbcode

如何将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网址标签的理想结果应为:

<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]标记的双引号部分,则将该值用作href值,并保留[url]标记的innerHTML作为生成的<a>标记的innerHTML。

如果网址不在双引号部分但位于开始和结束[url]标记之间,则将该值用作href值和{{1}的innerHTML }。

2 个答案:

答案 0 :(得分:3)

  

更新:Casimir的评论解决方案更直接/更干净。

代码:(Demo)(Pattern Demo

echo preg_replace('~\[url(?|]((https?://[^[]+))|(?:="(https?://[^"]+)")](.+?))\[/url]~i', '<a href=\"$1\">$2</a>', $bbcode);

通过将模式中第一个替代项的捕获加倍,您可以确保始终使用$1$2来应用替换字符串。

以下a slightly extended variation of the pattern考虑​​单引号而不引用。

(上一个解决方案的开始)

使用preg_match_callback(),您可以确定在开头[url]标记内是否提供了网址 - 在这种情况下,您需要保留位于开始和结束之间的文字标签

如果代码之间的文字是网址,则可以在<a>代码字符串的两个位置使用它。

无效的字符串不会被转换。

代码:(Demo)(Pattern Demo

$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

回调函数评估匹配数组($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]
)

答案 1 :(得分:2)

您可以使用

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

a demo on regex101.com

<小时/> 细分:

(?i)                   # case insensitive
\[url                  # [url
(?|                    # branch reset
    ="(?P<url>[^"]+)   # either ="..."
    |                  # or
    \](?P<url>[^][]+)  # ]...[/url]
)

在任何一种情况下,您都需要“url”组。