【问题标题】:URL detection and BB-Style tags (regex, look-ahead issue)URL 检测和 BB 样式标签(正则表达式、前瞻问题)
【发布时间】: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.com
http://www.example.com
http://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; ...) 使其具有原子性。
  • 您能详细说明一下吗?我尝试使各种组原子化,但没有成功(但我不确定我是否完全理解原子组)。

标签: php regex preg-replace-callback negative-lookahead


【解决方案1】:

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

一步一步:

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

[^\s()<>]+

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

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 匹配模式可能是值得的。请注意不要在匹配中包含括号:)
猜你喜欢
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多