繁体   English   中英

为什么这个JavaScript正则表达式在浏览器中崩溃了?

[英]Why does this JavaScript regex crash in the browser?

据我所知, [ab](a|b)在尝试匹配一组字符时应该是等效的。 现在,看看两个正则表达式:

/^(\s|\u00A0)+|(\s|\u00A0)+$/g
/^[\s\u00A0]+|[\s\u00A0]+$/g

它们都应该匹配字符串开头和结尾的空格(有关正则表达式本身的更多信息,请参阅Polyfill 这里的部分)。 当使用方括号时,一切都运行良好,但是当你切换到括号时,即使是最简单的字符串也会导致浏览器无限期地运行。 这种情况发生在最新的Chrome和Firefox上。

这个jsfiddle演示了这个:

a ="a                                                               b";

// Doesn't work
// alert(a.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g,''));
// Works
alert(a.replace(/^[\s\u00A0]+|[\s\u00A0]+$/g,''));

这是一个疯狂的怪癖与浏览器的正则表达式引擎的实现或还有其他关于正则表达式的算法导致这个?

您所看到的问题称为灾难性的回溯,如解释在这里

首先,让我简化并澄清您的测试用例:

a = Array(30).join("\u00a0") + "b";  // A string with 30 consecutive \u00a0
s = Date.now();
t = a.replace(/^(\s|\u00A0)+$/g, '');
console.log(Date.now()-s, a.length);

发生的事情是表达式的第二部分: ^(\\s|\ )+$ 请注意\\s匹配许多空白字符,包括本身。 这意味着\\s匹配30个字符中的每一个。

因此,如果您尝试将字符串与/(\\s|\ )+/匹配,您会发现30个字符的空格模式的2^30不同组合中的每一个都将导致匹配。 当正则表达式匹配器匹配前30个字符时,它将尝试匹配字符串( $ )的结尾并失败,因此它回溯并最终尝试所有2^30组合。

您的原始字符串(在jsfiddle中,其中stackflow中的那个已经被“规范化”到所有空格)是a \  \  ... \  b大约30 字符a \  \  ... \  b ,因此浏览器花了大约2^30努力去完成。 它不会挂起浏览器,但需要几分钟才能完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM