URL 检测和 BB 样式标签(正则表达式、前瞻问题)

Posted

技术标签:

【中文标题】URL 检测和 BB 样式标签(正则表达式、前瞻问题)【英文标题】:URL detection and BB-Style tags (regex, look-ahead issue) 【发布时间】:2013-02-06 23:24:35 【问题描述】:

所以我正在构建一个小型 CMS,并且我想避免在内容编辑器中允许 html。出于这个原因,我想检测文本中的原始 URL 以及支持类似 BB 的标签,以便更好地自定义。

www.example.com
[link http://www.example.com]Click me[/link]

不幸的是,我对正则表达式还很陌生,我似乎无法使其正常工作。我在字符串上运行两个正则表达式:第一个检测原始 URL,第二个检测类似 BB 的 URL。后者似乎工作得很好,但第一个会干扰,并且也会转换包含在标签中的 URL。

我从找到here 的一段代码开始,并做了一些补充。

这是非标记网址的代码:

/* don't match URLs preceeded by '[link ' */
(?<!\[link\s)
(
    /* match all combinations of protocol and www. */
    (\bhttps?://www\.|\bhttps?://|(?<!//)\bwww\.)

    /* match URL (no changes made here) */
    ([^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))

    /* but don't match if followed by [/link] - THIS DOESN'T WORK */
    (?!\[/link\])
)

www. 之前的负面回溯是因为/ 不是单词字符,没有它类似于

 [link http://www.example.com]example[/link]

http:// 之后仍然会匹配。

上面的正则表达式产生以下匹配(用http://gskinner.com/RegExr/测试,匹配是bold。我不得不在http://之后添加空格,因为我不允许发布更多的网址):

www.example.comhttp://www.example.comhttp://example.com [链接http://www.example.com]no问题1[/link] [链接www.example.com]没问题2[/link] [链接http://www.example.com]http://www.example.com[/link]

我尝试移动否定的前瞻并玩弄括号(非常漫无目的),但没有成功。

为了完整起见,这里是标签匹配的正则表达式(似乎有效):

(?:\[link\s)(\bhttps?://|\bwww\.|\bhttps?://www\.)([^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))\](.*)(?:\[/link\])

我相信有人可以立即发现错误。

提前非常感谢!

【问题讨论】:

(?!\[/link\]) 前瞻将失败,因为 PCRE 将连续缩短之前的匹配以成功。您可能需要使 URL 匹配超级贪婪。尝试(?&gt; ...) 使其具有原子性。 您能详细说明一下吗?我尝试使各种组原子化,但没有成功(但我不确定我是否完全理解原子组)。 【参考方案1】:

我已经采用了您的正则表达式,并使用您提供的示例将其插入到 regexr 中,并尝试使其工作。

一步一步:

1) 原始正则表达式:http://regexr.com?33snj。这个正则表达式也匹配 [/link] 的问题在于 URL 匹配位:

[^\s()<>]+

这也将匹配左括号字符“[”,因此匹配不会在遇到 [/link] 位时停止。可以说 [ 字符是有效的 URI 字符,但这仅在极少数情况下(有关更多信息,请参阅 this*** 帖子)。

2) 我决定继续使用您的正则表达式,但将左括号字符添加到否定字符列表中:

[^\s()<>[]+

这会让你陷入另一个问题。见http://regexr.com?33snp。由于回溯,引擎现在在最后找到了一种绕过负前瞻的方法。

3) 一旦您使 URL 匹配组原子化(通过将 ?> 添加到捕获组的开头),引擎就会停止回溯,我们已经达到了预期的结果。

(?<!\[link\s)((\bhttps?://www\.|\bhttps?://|(?<!//)\bwww\.)(?>[^\s()<>[]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))(?!\[/link\]))

看到它在行动http://regexr.com?33sns。

【讨论】:

我实际上也尝试将左括号添加到否定字符,但由于担心不再检测到某些 URL(除了它不起作用,因为我没有使捕获组原子)-但是,通过您提供的链接,我现在对此解决方案非常满意。非常感谢! 我理解这种担忧。这个 url 匹配很简单,但可以完成工作。我不会只允许括号。相反,我会去识别 url 中的 IPv6 地址。 另外我不知道你为什么需要这个 (?:([\w\d]+)|([^[:punct:]\s]|/)) 在 url 匹配位后面.研究更好的 url 匹配模式可能是值得的。请注意不要在匹配中包含括号:)

以上是关于URL 检测和 BB 样式标签(正则表达式、前瞻问题)的主要内容,如果未能解决你的问题,请参考以下文章

js-正则表达式边界符和前瞻后顾的使用-保证你看明白

正则表达式包含和排除不前瞻

Prometheus(公制)使用逆正则表达式匹配/负前瞻重新标记配置

JS 正则表达式否定匹配(正向前瞻)

sed:具有反向前瞻匹配的嵌套组

[正则]前瞻