简单的AlphaNumeric Regex(单个间距),没有灾难性的回溯

时间:2014-12-01 21:22:56

标签: regex backtracking

我有以下REGEX表达式(可行)以允许Alpha-Numeric(以及'-)并且没有双倍间距:

  ^([a-zA-Z0-9'-]+\s?)*$

由于嵌套分组,这可以发生灾难性的回溯 - 这很糟糕!

如何简化此表达式以避免灾难性回溯? (理想情况下,这不允许在第一个和最后一个字符中使用空格)

1 个答案:

答案 0 :(得分:2)

说明

嵌套组不会自动导致灾难性的回溯。在你的情况下,这是因为你的正则表达式退化为灾难性回溯的经典例子(a*)*

由于\s中的^([a-zA-Z0-9'-]+\s?)*$可选,但在输入中没有任何空格但字符超出允许列表时,正则表达式只会退化为^([a-zA-Z0-9'-]+)*$

您还可以考虑扩展原始正则表达式:

[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?...

由于\s是可选的,我们可以删除它:

[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+...

我们得到了一系列连续的[a-zA-Z0-9'-]+,它们将尝试各种方式在他们之间分配角色并夸大其复杂性。

解决方案

编写匹配token delimiter token ... delimiter token的正则表达式的标准方法是token (delimiter token)*。虽然可以重写正则表达式而不是重复token,但我建议不要重复它,因为它很难正确。为避免重复,您可能希望通过字符串连接来构造正则表达式。

按照上面的方法:

^[a-zA-Z0-9'-]+(\s[a-zA-Z0-9'-]+)*$

虽然你可以在这里看到重复的重复,但没有灾难性的回溯,因为正则表达式只能扩展到:

[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+...

并且\s[a-zA-Z0-9'-]是互斥的 - 只有一种方法可以匹配任何字符串。