更新时间:2023-02-22 22:25:54
更新:Casimir的评论解决方案更直接/更干净。
UPDATE: Casimir's commented solution is more direct/clean.
echo preg_replace('~\[url(?|]((https?://[^[]+))|(?:="(https?://[^"]+)")](.+?))\[/url]~i', '<a href=\"$1\">$2</a>', $bbcode);
通过将模式中第一个替代品的捕获加倍,您可以确保始终拥有 $ 1
和 $ 2
申请替换字符串。
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)
使用 preg_match_callback()
您可以确定在开头 [url]
标签内是否有提供的网址 - 在这种情况下,您将想要保留位于开始标记和结束标记之间的文本。
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.
如果标记之间的文本是网址,则在< a> 标记字符串。
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.
$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
)并有条件地生成并返回所需的输出。如果有任何匹配,则输出将包含:
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]
)
或
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]
)