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 匹配超级贪婪。尝试(?> ...)
使其具有原子性。
您能详细说明一下吗?我尝试使各种组原子化,但没有成功(但我不确定我是否完全理解原子组)。
【参考方案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 样式标签(正则表达式、前瞻问题)的主要内容,如果未能解决你的问题,请参考以下文章