How to convert bbcode url tag to an html hyperlink using the bbcode tag's values?

﹥>﹥吖頭↗ 提交于 2019-12-13 03:57:41

问题


How can I convert a bbcode [url] tag to an <a> tag with an href attribute and text between the opening and closing tag?

Here are some sample strings:

[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]

*Notice that the double quoted substring in the opening [url] tag is optional and impacts the desired output...

I've tried this pattern:

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

with something like:

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

My desired result from the above bbcode url tags should be:

<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>

In other words, if the url is in the double quoted portion of the opening [url] tag, then use that value as the href value and retain the innerHTML of the [url] tag as the innerHTML of the generated <a> tag.

If the url is not in the double quoted portion but is located between the opening and closing [url] tags, then use that value as both the href value and the innerHTML of the <a>.


回答1:


UPDATE: Casimir's commented solution is more direct/clean.

Code: (Demo) (Pattern Demo)

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

By doubling the capture of the first alternative in the pattern, you can ensure that you always have a $1 and $2 to apply to the replacement string.

Here is a slightly extended variation of the pattern that considers single quoting and no quoting.


(Start of previous solution)

By using preg_match_callback() you can determine if there was a url provided inside of the opening [url] tag -- in which case, you will want to preserve the text that is located between the opening and closing tags.

If the text between the tags IS the url, you use it in both places in the <a> tag string.

Invalid strings will not be converted.

Code: (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";
}

Output:

[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>
---

Pattern Breakdown:

~                    #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

The callback function assesses the elements in the matches array ($m) and conditionally generates and returns the desired output. If there are any matches, the output will either contain:

array(
    0 => [the fullstring match]
    1 => [the url of a bbcode tag that does not have a quoted url]
)

or

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]
)



回答2:


You could use

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

See a demo on regex101.com.


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

In either case, you'd need the group "url".



来源:https://stackoverflow.com/questions/50197539/how-to-convert-bbcode-url-tag-to-an-html-hyperlink-using-the-bbcode-tags-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!