/^( ?(-|\*|_) ?){3,}[ \t]*$/gm
在大多数情况下都可以正常工作。但是,以下输入:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - abc
使该库非常缓慢(在nodeJS上花费约10秒,在浏览器中花费更长的时间)。添加的破折号越多,获得的速度就越慢。 (stackexchange使用类似的正则表达式来解析
<hr>
)如何使其更快?
#1 楼
恭喜,您这里的回溯确实非常糟糕。还记得2016年7月的StackOverflow中断吗?因为在那里有很好的解释。如果您想知道,那就是111,803我们可以通过从匹配器图中删除替代路径来大大减少步骤数。这可以通过消除可选项,删除非贪婪量化和其他一些技巧来完成。在这种情况下,我们可以使用一个与以下事实有关的简单技巧:仅在星号,短划线和下划线之间留一个空格:
在您的示例中将模式不匹配的识别降低到仅272个步骤。请注意,我很随意地将您的ORing捕获组替换为明显“更轻松”的字符类。如果我们忽略了您使用的捕获组导致不匹配和附加步骤的事实,该功能基本上是等效的。
此更改使正则表达式引擎更容易确定匹配。
您的模式和我的模式之间唯一的显着区别是,我的模式无法识别“非标准”(就markdown而言):
/^( ?[-_*]){3,} ?[\t]*$/
以及它没有灾难性的回溯的事实:)在regex101上查看一下评论
\ $ \ begingroup \ $
也许值得注意的是,某些Markdown风格(例如CommonMark)确实在破折号/星号/下划线之间留有多个空格。另一方面,CommonMark要求所有非空白字符都必须相同,而Tivie的正则表达式和您的正则表达式都不一样。
\ $ \ endgroup \ $
–伊尔马里·卡洛宁(Ilmari Karonen)
16/12/19在13:51
\ $ \ begingroup \ $
顺便说一句,我相信您确实引入了另一个小的区别:您的正则表达式将不匹配,例如“ --- \ t \ t”。要解决此问题,您可以将其更改回/ ^(?[-_ *]){3,} [\ t] * $ /;因为(?[-_ *]){3,}无论如何都必须以非空白字符结尾,因此不会造成任何额外的回溯。另外,如果希望在破折号之间留出多个空格以实现向后兼容性,我相信/ ^?([-_ *] *){3,}(\ t [\ t] *)?$ /甚至是/ ^?( [-_ *] {0,2}){3,} [\ t] * $ /(如果要匹配与原始正则表达式完全相同的字符串)应做到这一点而不会造成过多回溯。
\ $ \ endgroup \ $
–伊尔马里·卡洛宁(Ilmari Karonen)
16/12/19在14:03
#2 楼
我刚刚注册,所以我只能发布答案,而不能对Vogel612的其他不错的答案发表评论。 。您可以通过在其后面添加{3,}
来实现。在这种情况下,它是完全等效的,因为添加+之前和之后的部分不会重叠(可选空格除外)。以下正则表达式仅需196个步骤即可找到不匹配的内容:可以将其降至103:^( ?(-|\*|_) ?){3,}+[ \t]*$
评论
\ $ \ begingroup \ $
虽然这是一个很棒的技巧,但不幸的是,标准的javascript正则表达式引擎不接受将其作为正则表达式:(
\ $ \ endgroup \ $
–Vogel612♦
16 Dec 19'在16:03
\ $ \ begingroup \ $
抱歉我不太会JavaScript,并在您提供的链接上对其进行了测试。我没有注意到它默认加载了PHP而不是JS。
\ $ \ endgroup \ $
– TimVdE
16 Dec 19'在16:06
#3 楼
现在我可能是错的,但我可以匹配:-------从3开始,
-----从3开始,
尽管不匹配'abc'示例(或在行中的任何位置向混合中抛出非水平规则符号的任何行),但执行以下操作:
/^ *[\-\*_] *[\-\*_] *[\-\*_][\-\*_ \t]*$/
分66步。我担心的是,我不确定您是否要在水平规则符号之间留出多个空格。因为这肯定使您可以在符号之间添加额外的空格。 />
您可以在regex101上查看模式
评论
\ $ \ begingroup \ $
2年前,我忘了回复(并给了您信用),但最终还是使用了您的正则表达式的变体
\ $ \ endgroup \ $
–Tivie
18-10-8在1:19
评论
灾难性的回溯我两次将库名称误读为Slowdownjs。我也必须进行灾难性的回溯。
如果您想知道为什么要求代码解释不合时宜,请阅读我们的离合页面,让我知道是否仍然不清楚。