0

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;
}
2
  • I had to click on this question simply because of the title. Commented Jun 24, 2017 at 15:53
  • How could a string end with a digit, a small letter and a capital letter at the same time? Commented Jun 24, 2017 at 15:56

2 Answers 2

1

A couple of things:

  • regex are not necessarily the best way to express such constraints. Going through the password a single time while counting the number of occurrences of each character type would solve this just as well.

  • you're using binary OR (|) instead of logical OR (||). For booleans it will behave the same but you almost certainly did not do it on purpose.

  • the dollar at the end of your regex means end of string. You don't really care whether the character is at the beginning, middle or end of the string, you only want it to be somewhere.

  • matches attempts to match the entire string. Your code would work using find instead or adding .* on both ends of each regex.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, there are important observations for me, apart from the fact that I know about features of binary (|).
0

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.

1 Comment

Thanks a lot, i should read much more about using regex and forming it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.