正则表达式需要很长时间才能完成。

3

我想匹配一个结构如下的行:

  • 行首
  • 多个' - '
  • 可能有一个空格(也可能更多)
  • 至少一个字符
  • 可能有更多的字符和空格
  • 可能有一个空格(也可能更多)
  • 多个' - '
  • 行尾

所以我写了这样的正则表达式:

new Regex(@"^\-{2,}\s*(\w+(\w+|\s)*)\s*\-{2,}$");

当我尝试匹配以下行时,这需要很长时间才能完成(没有等待它完成):

-------- Variable used for recipe visualization only - Not loaded into PLC --------

我认为其中有很多匹配项,使正则表达式枚举所有这些匹配项变得困难,但我不确定。

环境信息:Windows 7,框架3.5

谢谢

编辑:感谢您的帮助,我想出了一个可行的正则表达式:

^-{2,}\s*(?!\-)(\w(?:\w|\s|\-)+)(?<!\-)\s*-{2,}$

所以,这个解释是:
  • 行首
  • 至少两个“-”
  • 可能有一个或多个空格
  • 没有更多的“-”
  • 至少一个字符
  • 可能有更多的字符、空格或“-”
  • 没有更多的“-”
  • 可能有一个或多个空格
  • 至少两个“-”
  • 行尾
如果您发现有什么错误,请告诉我。

1
这不会匹配,因为 "only - Not" 中有一个内部破折号。 - juharr
1
你的问题在于你没有将中间的 "-" 捕获。 - Jonesopolis
1
我刚在 https://myregextester.com/index.php 上尝试了一下,它只用了0.018301秒就运行完了。但是在C#中运行需要非常长的时间,但是如果去掉内部破折号,它会加快速度。 - juharr
@juharr和Jonesopolis,感谢你们的回答。但是为什么它不能只返回false而不是长时间运行呢? - nkoniishvt
1
我期望这部分负责:(\w+(\w+|\s)*)。基本上,只要一系列空格保持不变,就允许单词和空格序列的任何分区。由于整个表达式不匹配,回溯将依次访问所有可接受的分区。尝试使用 (\w+(\s+\w+)*) 替换它。 - collapsar
显示剩余3条评论
1个回答

4

展开嵌套分组为

^-{2,}\s*(\w+(?:\s+\w+)*)\s*-{2,}$
             ^^^^^^^^^^^ 

否则,您的模式将容易出现灾难性回溯
请查看正则表达式演示 或者,使用原子组来禁用任何返回到替换组的回溯:
^-{2,}\s*((?>\w+(?:\w+|\s)*))\s*-{2,}$
          ^^^              ^ 

请查看 这个正则表达式演示

通常,避免在较长的模式中使用嵌套量词的交替(例如(\w+ | \s)* )。


编辑了我的答案,包括适用于此情况的正则表达式。您能否看一下并告诉我是否有什么问题?谢谢。 - nkoniishvt
2
正则表达式不是最优的。 (?!-) 完全是多余的,因为下一个子模式是 \w,因此前瞻检查结果始终为 true。我会重写为 ^-{2,}\s*(\w+(?:[\s-]+\w+)*)\s*-{2,}$(然后 (?<!-) 不是必要的,因为最后一个可选空格和连字符之前唯一可能的字符是单词字符。请注意,在字符类外部不必转义 - - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接