6

这个问题是以下帖子的后续: Javascript regex: Find all URLs outside <a> tags - Nested Tags

我发现代码:

\b((https?|ftps?):\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

http与像这样单独执行它相比,效率极低ftp

\b(https?:\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

\b(ftps?:\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

以下是 regex101.com 上的示例:

然而,在我的一个 HTML 页面中,这些代码比较为85628步与7258 + 795步,这太疯狂了。

据我所见,使用(x|y)模式会减少执行长度,但这里可能出于一个奇怪的原因,否则会这样。

任何帮助,将不胜感激。

4

2 回答 2

3

看来您是灾难性回溯的受害者。

这个正则表达式只需要 3492 步就可以解决问题:

\b(?>(https?|ftps?):\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

我所做的只是使第一组成为原子组,导致引擎在匹配后丢弃所有回溯选项。

这在您的情况下是正确的:您现在可以将其视为两部分,“查找 URL”然后“使用否定前瞻来决定我们是否要保留它”。当前瞻失败时,您的原始正则表达式将继续回溯到 url 匹配表达式。该[^"<\s]+块会产生一些符号,然后它会再次尝试前瞻,然后产生更多的符号,然后再试一次,依此类推......

添加该https?|ftps?部分使其变得更糟的原因是,这提供了一个额外的回溯源(丢失了可选的 s),从而允许所有后来的回溯重新发生。

您知道 regex101.com 在左侧工具栏上有一个“正则表达式调试器”选项吗?如果你使用它,它会解释你的正则表达式是如何匹配的,所以你可以(就像我刚才所做的那样)找出疯狂的回溯在哪里。

奖励编辑:进一步改进的仅需要 3185 步:

\b(?>ht|f)tps?:\/\/(?>[^"<\s]+)(?![^<>]+>|[^"]*?<\/a)
于 2016-03-12T10:19:09.907 回答
0

如果您要查找文档中的所有链接,那么解决方案就是这样。它返回一个数组

document.anchors

于 2016-03-12T09:23:41.970 回答