我有以下REGEX表达式(可行)以允许Alpha-Numeric(以及'
和-
)并且没有双倍间距:
^([a-zA-Z0-9'-]+\s?)*$
由于嵌套分组,这可以发生灾难性的回溯 - 这很糟糕!
如何简化此表达式以避免灾难性回溯? (理想情况下,这不允许在第一个和最后一个字符中使用空格)
答案 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'-]
是互斥的 - 只有一种方法可以匹配任何字符串。