Search code examples
javaregexcycle

Infinite loop using regex


What's wrong with my regex or statement in cycle? I need 8-chars combination with one digit, one letter in upper case and one in lower case minimum. But I get a non-stop cycle.

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;
}

Solution

  • The problem is Java's matches() must match the whole string to return true, so your loop condition will always be true (the input can't both all digits and all letters).

    There are two ways to fix your problem:

    1) Add .* to each end of you regexes:

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

    2) Use one, albeit more complex, regex:

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

    The last option also checks that the length is 8.

    Also note that you don't need ^ or $ with matches() - they are implied by the contract.