【发布时间】:2013-04-29 20:16:41
【问题描述】:
我们的用户名验证有以下规则:
- 用户名可以包含字母数字字符
- 用户名可以有下划线、连字符或句点
- 现在假设用户名是 ASCII 格式
- 用户名不能以句点开头或结尾
- 用户名不能开始、结束或有空格
我们有以下相同的正则表达式:
^(([a-zA-Z0-9]+[_-]*[a-zA-Z0-9]*)([\\.]*[a-zA-Z0-9])*)+$
现在尝试匹配特定的字符串,CPU 使用率呈指数增长。例如:
M45766235H.M96312865E@EXAMPLE.COM
显然,像上面这样匹配字符串应该会立即失败,但我想知道为什么它会占用这么多 CPU 周期。最终代码:
import java.util.regex.*;
public class R {
static final Pattern namePattern = Pattern.compile("^(([a-zA-Z0-9]+[_-]*[a-zA-Z0-9]*)([\\.]*[a-zA-Z0-9])*)+$");
public static void main(String... args) {
final String userName = "M45766235H.M96312865E@EXAMPLE.COM";
Matcher matcher = namePattern.matcher(userName);
System.out.println(matcher.matches());
}
}
在不同的行中,我像下面这样重写了正则表达式,并且效果很好:
^[\\w]+[\\w-_\\.]*[\\w]+$
【问题讨论】:
-
这可能是由于一个或多个量词 (
+) 封装了整个正则表达式,导致回溯导致您观察到大量 CPU 周期。 -
这听起来像是catastrophic backtracking...
-
@Vulcan - 感谢您带来全局
(+)量词,但它是否也取决于用户名的长度?像 username@ 一样简单会立即失败。