使用正则表达式的无限循环

Infinite loop using regex

我的正则表达式或循环语句有什么问题?我需要 8 个字符的组合,一个数字,一个大写字母和一个小写字母最少。 但是我得到了一个不间断的循环。

public static ByteArrayOutputStream getPassword() throws IOException{

    char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
    Random random = new Random();
    String out = "";
    ByteArrayOutputStream stream = new ByteArrayOutputStream();;
    while (!out.matches("[0-9]+$") | !out.matches("[a-z]+$") | !out.matches("[A-Z]+$")) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            char c = chars[random.nextInt(chars.length)];
            sb.append(c);
        }
        out = sb.toString();
    }
    stream.write(out.getBytes());
    return stream;
}

问题是 Java 的 matches() 必须匹配 整个字符串 到 return true,所以你的循环条件将始终为真(输入不能同时包含所有数字 所有字母)。

有两种方法可以解决您的问题:

1) 将 .* 添加到正则表达式的每一端:

if (!out.matches(".*[0-9].*") | !out.matches(".*[a-z].*") | !out.matches(".*[A-Z].*")) 

2) 使用一个正则表达式,尽管更复杂:

if (!out.matches("(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8}"))

最后一个选项还检查长度是否为 8。

另请注意,您不需要 ^$matches() - 它们由合同暗示。

几件事:

  • 正则表达式不一定是表达此类约束的最佳方式。在计算每种字符类型的出现次数的同时检查一次密码也可以解决这个问题。

  • 您使用的是二进制 OR (|) 而不是逻辑 OR (||)。对于布尔值,它的行为是一样的,但你几乎可以肯定不是故意的。

  • 正则表达式末尾的美元表示 字符串结尾。你并不真正关心字符是在字符串的开头、中间还是结尾,你只希望它在 某处.

  • matches 尝试匹配整个字符串。您的代码可以使用 find 代替或在每个正则表达式的两端添加 .*