如何消除此正则表达式的缓慢性?

时间:2019-03-21 21:38:05

标签: regex

我有以下正则表达式:

(\d+\s+[-]\s+.*?(?=\s+-)|\d+\s+[-].*)

正则表达式将使用此文本

"Option 01 - Random phrase - Top Menu",
"Option 02 - Another Random Phrase - Su Menu",
"Option 03 - More 01 Phrase - Menu",
"Option 04 - More Phrase -",
"Option 05 - Simple Phrase"

要这样住

01 - Random phrase ",
02 - Another Random Phrase ",
03 - More 01 Phrase ",
04 - More Phrase ",
05 - Simple Phrase ",

此Regex的功能是获取以数字开头的破折号,并在最后一个破折号之前。例如:

  • dfhdjfhdjf 01-文本-dkfdçsjf

当最终没有踪迹时,基本上会发生这种情况:

  • dfhdjfhdjf 01-文本文本dkfdçsjf

但是,在 max_execution_time 上调试此正则表达式会导致您需要63到122个步骤。也就是说,此正则表达式非常慢。

在批评这个问题之前,我已经阅读了正则表达式的所有文档,我想让您知道我所指的是特定术语..一个需要解决的问题。毕竟,这不是网站吗?

告诉我,我该如何解决该正则表达式的缓慢性?

3 个答案:

答案 0 :(得分:5)

您不必担心在regex101.com上看到的步骤,因为C#regex库非常可靠。如果您在regex101上使用很长的字符串测试像(?s)a.*?b这样的简单正则表达式,它将报告灾难性的回溯,而在C#代码中也可以正常工作。

有一种方法可以改进您的模式,因为它有一些冗余:请参见重复的\d+\s+[-]模式。

您需要的只是

\d+\s+-.*?(?=\s+-|$)

请参见regex101RegexStorm上的正则表达式演示。

如果.*?(?=\s+-)仅在-后有空格时才匹配,请使用

\d+\s+-(?:\s.*?(?=\s+-)|.+)

查看另一个demo 1(较少的步骤:))/ demo 2

如果您想对其进行进一步的优化,则可能需要研究导致该问题的unroll-the-loop principle

\d+\s+-(?:\s+\S*(?:\s(?!\s*-)\S*)*|.+)

请参见this regex demo(最小步数)。

在这里,\S*(?:\s(?!\s*-)\S*)*.*?(?=\s+-|$)等效(几乎),但是效率更高,因为在“批”中匹配高达空格的块,仅在以下情况下才检查连字符遇到空格。

详细信息

  • \d+-1个以上数字
  • \s+-超过1个空格
  • --连字符
  • .*?(?=\s+-|$)-尽可能少的0个字符,直到第一次出现的1+个空格和-或直到字符串的末尾。
  • (?:\s.*?(?=\s+-)|.+)-非捕获组:
    • \s.*?(?=\s+-)-空格,最少0个字符,最多1个空格和-
    • |-或
    • .+-字符串的其余部分。
  • \S*(?:\s(?!\s*-)\S*)*
    • \S*-0 +个非空白字符
    • (?:\s(?!\s*-)\S*)*-重复0次或更多次
      • \s-空格
      • (?!\s*-)-后面没有0+空格和-
      • \S*-0 +个非空白字符

答案 1 :(得分:2)

您也可以尝试\d+\s+-[^-]*来获得所需的内容。到目前为止,步骤数最少。或者,您可以添加\d+\s+-[^-]*(?=\s),以防需要在-之前剪切它。 demo

答案 2 :(得分:1)

正如其他人在评论中指出的那样,尚不清楚Regex应该做什么,因为您似乎不想从潜在的匹配中捕获任何东西。但是无论如何,我还是建议使用以下正则表达式,它将选项字符串解析为其基本组件:

^[^\d]*\d+\s+-\s+.*?(?:\s+-\s+.*?)?$

从此开始,您可以在要捕获的部分周围添加括号。例如:

^[^\d]*(\d+)\s+-\s+(.*?)(?:\s+-\s+(.*?))?$

这将捕获选项号和破折号之间的文本。对于选项04和05,第三次捕获将为空。

编辑:现在,问题的作者已经阐明了应该捕获哪些子字符串,我想这个简单明了的正则表达式是合适的:

\d+[^-]*-[^-"]*

它捕获选项号,搜索第一个破折号,然后捕获直到下一个破折号或引号的所有内容:

<01 - Random phrase >
<02 - Another Random Phrase >
<03 - More 01 Phrase >
<04 - More Phrase >
<05 - Simple Phrase>

请注意,此处仅添加了尖括号以显示尾随空格。这就是你想要的吗?