URL检测和BB风格标签(正则表达式,前瞻性问题)

问题描述:

所以我正在构建一个小型CMS,并且我想避免在内容编辑器中允许使用HTML。出于这个原因,我想检测文本中的原始URL以及支持类似BB的标签,以获得更好的定制。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/测试,比赛都在大胆我不得不http://后添加空格,因为我不能发布更多的网址。):

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

我试着走动负前瞻并用括号(非常漫无目的地)玩,没有成功。

为了完整起见,这里的标记匹配的正则表达式(这似乎工作):

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

我敢肯定有人可以立即发现错误。

非常感谢!

+0

'(?!\ [/ link \])'lookahead将失败,因为PCRE会连续缩短前一个匹配的成功。您可能需要使URL匹配超级贪婪。尝试'(?> ...)'使其成为原子。 – mario 2013-02-21 15:15:16

+0

你能再详细一点吗?我试图让各个小组成为原子,但没有成功(我不确定我是否完全理解原子组)。 – psalz 2013-02-22 11:42:46

我已经采取了你的正则表达式,用你给出的例子试图使它成为正则表达式,并试图使它正常工作。

一步一步:

1)原正则表达式:http://regexr.com?33snj。为什么这个正则表达式的[/链接]也匹配的问题是在URL匹配位:

[^\s()<>]+ 

这也将匹配开放括号字符“[”,因此匹配在遇到[/链接不会停止]位。有人可能会认为[字符是一个有效的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

+0

我实际上也尝试过为反义字符添加左括号,但由于担心某些URL不再被检测到(除了因为我没有使捕获组原子化而不工作),所以停止继续此解决方案 - 但是,通过您提供的链接,我现在对此解决方案非常满意。非常感谢! – psalz 2013-02-24 11:21:11

+0

我明白这个问题。这个URL匹配很简单,但是完成这项工作。我不会只允许括号。相反,我会去认识IPv6地址的URL。 – 2013-02-24 19:31:54

+0

还有我不知道你为什么需要这个(:\([\ W \ d] + \)|([^ [:PUNCT:] \ s] | /?))的URL匹配有点落后。您可能需要一段时间来研究更好的url匹配模式。只是要小心不要在括号中包括括号:) – 2013-02-24 19:36:05