Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/421.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 你能解释一下为什么这些正则表达式很慢吗_Javascript_Regex - Fatal编程技术网

Javascript 你能解释一下为什么这些正则表达式很慢吗

Javascript 你能解释一下为什么这些正则表达式很慢吗,javascript,regex,Javascript,Regex,最近我在代码中发现了以下正则表达式。由于它所检查的字符串相当大,它冻结了浏览器。在运行一些实验时,我使用以下代码测量了时间 var s='Lorem ipsum door sit amet,rhoncus nam sem feugiat,vel vel,viverra ultrices interdum。沃里克·康格。在设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面。白骨木兰(Magnis metus nulla

最近我在代码中发现了以下正则表达式。由于它所检查的字符串相当大,它冻结了浏览器。在运行一些实验时,我使用以下代码测量了时间

var s='Lorem ipsum door sit amet,rhoncus nam sem feugiat,vel vel,viverra ultrices interdum。沃里克·康格。在设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面。白骨木兰(Magnis metus nulla mauris dictum ligula),白骨木兰(odio facilisis nullam laoreet)。阿利奎姆·汀西德·埃尼坐在我旁边。二者缺一不可,侵权行为造成的设备损坏。埃吉特是我的朋友。这是一个令人信服的事实,或者是一个与欧盟孕妇有关的事实。伊普苏姆万岁,佩纳蒂布斯万岁,波苏尔万岁,欧盟万岁,自由精英万岁。自由的布兰迪特·马蒂斯·米·萨皮恩,艾库利斯·维西·康瓦利斯,在自由的世界里,在前庭里,是一种粗糙的元素;
对于(变量i=0;i<3;i++){
s+=s;
}
开始=新日期().getTime();
s、 匹配(/AAA/i)
停止=新日期().getTime();
log(“AAA take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/BBB/i)
停止=新日期().getTime();
log(“BBB take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/CCC/i)
停止=新日期().getTime();
log(“CCC take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/.*(AAA | BBB | CCC)。*/i)
停止=新日期().getTime();

log(“Combined take”+(stop-start)+“ms”)
您在以前的测试中没有包含
*
,导致您的
匹配很快返回false

在这里,您可以看到每个测试运行大约需要
30ms

全局仍只需
40ms

除此之外,使用
s.match(/AAA | BBB | CCC/i)
会更快

var s='Lorem ipsum door sit amet,rhoncus nam sem feugiat,vel vel,viverra ultrices interdum。沃里克·康格。在设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面,设备方面。白骨木兰(Magnis metus nulla mauris dictum ligula),白骨木兰(odio facilisis nullam laoreet)。阿利奎姆·汀西德·埃尼坐在我旁边。二者缺一不可,侵权行为造成的设备损坏。埃吉特是我的朋友。这是一个令人信服的事实,或者是一个与欧盟孕妇有关的事实。伊普苏姆万岁,佩纳蒂布斯万岁,波苏尔万岁,欧盟万岁,自由精英万岁。自由的布兰迪特·马蒂斯·米·萨皮恩,艾库利斯·维西坐在康瓦利斯,在自由的世界里最美,在前庭的世界里最美
对于(变量i=0;i<3;i++){
s+=s;
}
开始=新日期().getTime();
s、 匹配(/.*AAA.*/i)
停止=新日期().getTime();
log(“AAA take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/.*BBB.*/i)
停止=新日期().getTime();
log(“BBB take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/.*CCC.*/i)
停止=新日期().getTime();
log(“CCC take”+(停止-启动)+“ms”)
开始=新日期().getTime();
s、 匹配(/.*(AAA | BBB | CCC)。*/i)
停止=新日期().getTime();

log(“Combined take”+(stop-start)+“ms”)
/AAA/i
/BBB/i
/CCC/i
/.*(AAA | BBB | CCC)的区别不仅在于交替捕获组的使用,而且在于
*/code>模式

/.*(AAA | BBB | CCC)。*/i
模式会减慢匹配速度,因为第一个
*
是贪心点模式。其工作方式如下:

  • 它会抓取它能匹配的所有字符(除换行字符以外的0个或多个CHSR),因此,基本上,它会抓取整个行
  • 然后,它必须匹配
    AAA
    BBB
    CCC
    ,因此回溯开始:引擎从匹配结束时产生一个字符,并尝试匹配其中一个替代项
  • 如果缺少替代项,或者它们位于很长字符串的开头,则引擎将徒劳地尝试容纳字符串的一部分以进行捕获组匹配
请参见可视化回溯步骤

因此,要确定一行/字符串是否包含这三个选项中的任何一个,最好的方法就是使用

/(?:AAA|BBB|CCC)/i
因为这个正则表达式可以找到部分匹配(它不需要像Java的
string#match()
那样的完整字符串匹配)

如果您需要在多行字符串中查找具有其中一个备选项的行,最好逐行处理(例如,使用
\n
拆分),然后使用
.filter(x=>/(?:AAA | BBB | CCC)/i.test(x))


注意
(?:…)
是一个不创建子匹配的非捕获组,由于引擎不必为捕获分配额外的内存,因此开销较小。

只需使用
s.match(/(?:AAA | BBB | CCC)/i)
查找3个备选方案中的任何一个,如果需要从多行文本中获取整行,首先用
\n
将其拆分,并使用此正则表达式进行过滤。感谢Bram Vanroy-您能解释一下在正则表达式开始时“:”的作用吗?重点是
*
之前的
(AAA | BBB | CCC)
会导致大量回溯。非捕获组,
(?:…)
,比捕获组快,因为引擎没有为子匹配分配内存。我发布了答案,解释了为什么它慢。感谢Wiktor Stribiżew,被接受-有趣的是,当我打开该链接时,在线调试器冻结(无法向下滚动);-)当我减少了测试字符串的长度时,它起了作用。我想为了我想要的东西(只要检测到字符串中有任何单词),我可以从组合正则表达式中删除“*”,它将与单个正则表达式一样快one@szydan真的,谢谢。我接受了Wictor的答案,因为它包含一个解释+到在线调试器的链接