Javascript 正则表达式无限循环与大写字母相关



我在node中创建了一个正则表达式.js能够匹配看起来像URL的文本部分。但是,在某些文本上,我的正则表达式创建了一个无限循环!

整个正则表达式是:

/(((ftp|https?)://|(www.))?([a-zd]+-?)+.[a-zd/-._~:?#@!$&'*+,;=`]+)/gi

但是经过一番调试,我发现无限循环只是由这部分引起的:/((ftp|https?)://|(www.))?([a-zd]+-?)+./gi

> let r = /((ftp|https?)://|(www.))?([a-zd]+-?)+./gi
> const txt = "www.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_~:/?#@!$&'*+,;=`"
> r.test(txt)
^CError: Script execution interrupted. // infinite loop

我做了更多的测试来理解这个问题。首先,没有标志:

> r = /((ftp|https?)://|(www.))?([a-zd]+-?)+./
> r.test(txt)
true

令人惊讶的是,它有效!仅带有g标志的测试 2:

> r = /((ftp|https?)://|(www.))?([a-zd]+-?)+./g
> r.test(txt)
true

也有效!仅带有i标志的测试 3:

> r = /((ftp|https?)://|(www.))?([a-zd]+-?)+./i
> r.test(txt)
^CError: Script execution interrupted. // infinite loop

失败。。。所以我决定删除i标志并使用 A-Z 代替:

> r = /((ftp|https?)://|(www.))?([a-zA-Zd]+-?)+./
> r.test(txt)
^CError: Script execution interrupted. // infinite loop

不工作...有人了解问题吗?有解决方案吗?

这是一个灾难性的回溯。

为了避免这种现象,请尝试构建一个始终从左到右前进的正则表达式(即匹配失败将停止正则表达式,而不是让它尝试其他地方的某些子部分)。否则:不应该有几种方法来匹配字符串的一部分(否则正则表达式引擎会尝试所有方法,在某些情况下,这可能会导致指数大小的可能性树)。

试图了解您的真正目标,我可以提出以下解决方案:

/((ftp|https?)://|(www.))?([a-zd]+)(-[a-zd]+)*./gi

(这可能也更正确)

另一种解决方案是使用非回溯正则表达式引擎,例如 R2(是的,节点有一个绑定)。根据我的经验,节点中的 R2 比标准正则表达式引擎慢,因此只有当您有用户输入的正则表达式时才有意义,因为当您是正则表达式作者时,您通常可以找到非灾难性正则表达式。

最新更新