电子邮件类似的正则表达式灾难性回溯

时间:2016-10-25 18:04:57

标签: regex

我希望匹配可能被称为电子邮件开头的内容,即

  1. 1个字符(字母和数字中的任何一个字母)
  2. 0或1点
  3. 1个或更多字符
  4. 重复{第2和第3点}零次或多次
  5. @ 字符
  6. 我试图在Regex101上申请的正则表达式是\w(\.?\w+)*@

    我收到错误灾难性回溯。我究竟做错了什么?正则表达式是否正确?

2 个答案:

答案 0 :(得分:1)

问题

当字符串的一部分以许多不同的方式匹配正则表达式的一部分时,会发生“灾难性的回溯”,因此需要重复重试以确定该字符串是否实际匹配。一个简单的案例:正则表达式a+a+b匹配两个或更多a后跟一个b。如果您要在aaaaaaaaaaa上运行该问题,则会出现问题:首先,第一个a+匹配所有内容,第二个a+失败。然后,它尝试使用第一个a+匹配除了一个a之外的所有内容,第二个a+匹配一个a(这是“回溯”),然后失败b。但是正则表达式并不是“聪明”足以知道它可能会停在那里 - 所以它必须继续保持这种模式,直到它尝试每次分配给第一个和第二个给出一些a s。一些正则表达式引擎会意识到它们会像这样陷入困境,并在你看到错误后退出足够的步骤。

针对您的具体模式:您所拥有的内容与任何非零数量的字母或数字相匹配,并与.不能先成为.的任意数量混合,后跟@ 。唯一的附加限制是不能有两个相邻的点。实际上,这与我的示例相同:应用于包含*的部分的+就像+ - ed部分的多个副本一样。

原子分组

您可以尝试使用atomic grouping。这基本上说“一旦你找到任何匹配,不要回溯到它”。毕竟,如果你发现了一些/w,它就不会包含/.而且不需要重新检查 - 点不是字母或数字,这些都不是@

在这种情况下,结果将是\w(?>\.?\w+)*@。请注意,并非所有正则表达式引擎都支持原子分组,尽管您链接的那个。如果字符串只是匹配,则不会发生任何变化 - 如果它不匹配,或者包含不匹配,则该过程将采用更少的步骤。使用评论中的@ eddiem示例,它在原始的166311步骤中找到了两个匹配项,但只添加了623个步骤并添加了原子分组。

占有量词

另一种选择是占有性量词 - \w(\.?\w+)*+@意味着大致相同的事情。 *+,具体来说,就是“无论星星匹配什么,都不要在它内部回溯”。在上面的例子中,它匹配了558个步骤 - 但它的含义略有不同,因为它将所有重复一起视为一个原子值,而不是几个不同的原子值。我不认为这种情况有所不同,但在某些情况下可能存在差异。同样,并非所有正则表达式引擎都支持。

答案 1 :(得分:1)

当内部组包含至少一个可选子模式时,catastrophic backtracking通常出现在嵌套量词的情况下,使量化的子模式匹配与外部组之前的子模式相同的模式并且外部组不在模式的末尾。

Your regex causes the issue正确,因为(\.?\w+)*不在最后,有一个可选的\.?,表达式缩减为\w(\w+)*@

  

例如aaa.aaaaaa.a.aa.aa但现在aaa..aaaa.a

您需要的是

^\w+(?:\.\w+)*@

请参阅regex demo

  • ^ - 字符串的开头(以避免部分匹配)
  • \w+ - 一个或多个单词字符
  • (?:\.\w+)* - 零个或多个序列:
    • \. - 一个文字点
    • \w+ - 一个或多个单词字符
  • @ - 文字@字符。