我是Showdownjs的当前维护者,Showdownjs是PageDown(stackexchange的markdown解析器)所基于的markdown解析器。
/^( ?(-|\*|_) ?){3,}[ \t]*$/gm


在大多数情况下都可以正常工作。但是,以下输入:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - abc


使该库非常缓慢(在nodeJS上花费约10秒,在浏览器中花费更长的时间)。添加的破折号越多,获得的速度就越慢。 (stackexchange使用类似的正则表达式来解析<hr>

如何使其更快?

评论

灾难性的回溯

我两次将库名称误读为Slowdownjs。我也必须进行灾难性的回溯。

如果您想知道为什么要求代码解释不合时宜,请阅读我们的离合页面,让我知道是否仍然不清楚。

#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