Tim
Tim

Reputation: 1074

Java - Regex for Password

How can I construct a regular expression such that a password field I am making contains at least one number, at least one lowercase letter and at least one uppercase letter where order DOES NOT matter and anything can be in-between these characters?

I have tried this and got something similar: ".*\\d.*[a-z].*[A-Z].*" but that requires that the number comes first, the lowercase second and the uppercase last.

Upvotes: 1

Views: 448

Answers (3)

giorgiga
giorgiga

Reputation: 1778

Yours is not one of the use case regular expressions are particularly good at – if you're stuck with regular expressions, I guess you have no choice but to enumerate the 6 cases:

.*[0-9].*[a-z].*[A-Z].*|.*[0-9].*[A-Z].*[a-z].*|.*[a-z] ... | ...

Check with actual java code would be easier (and more readable):

String  password = "";
boolean complies = password.matches(".*[0-9].*")
                && password.matches(".*[a-z].*")
                && password.matches(".*[A-Z].*");

or (uglier, but possibly faster):

boolean complies = false;
{
    boolean hasDigit     = false;
    boolean hasLowercase = false;
    boolean hasUppercase = false;
    for (int i = 0; i < password.length(); i++) {
        char c = password.charAt(i);
        hasDigit     |= '0' <= c && c <= '9';
        hasLowercase |= 'a' <= c && c <= 'z';
        hasUppercase |= 'A' <= c && c <= 'Z';
        if (hasDigit && hasLowercase && hasUppercase) {
            complies = true;
            break;
        }
    }
}

Upvotes: 3

Vivek Viswanathan
Vivek Viswanathan

Reputation: 1963

One way to achieve this is by

1) First check for the presence of lower case letter by using a separate regex, say regex-1.

2) Next check if it contains numbers by using another regex.

3) Check for any other rule.

Breaking down the rules would solve the issue you are facing and also improves the way you report the error.

Upvotes: 3

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 299218

Regex is not suited for complicated scenarios like this. The only way you can implement it in regex is by listing all possibilities:

(abc|acb|bac|bca|cab|cba)

Where a, b, and c are sub-patterns that represent your individual requirements, e.g. abc would be .*\\d.*[a-z].*[A-Z].*, bac stands for [a-z].*.*\\d.*[A-Z].*, etc. Good luck in maintaining such a monster. My tip would be to create java constants for each of the parts:

private static final String DI = "\\d+";
private static final String LO = "[a-z]+";
private static final String UP = "[A-Z]+";
private static final String WI = ".*";
private static final String OR = "|";
private static final Pattern REGEX = Pattern .compile(
    WI + DI + WI + LO + WI + UP + WI + OR
  + WI + LO + WI + DI + WI + UP + WI + OR
  // etc
);

Upvotes: 1

Related Questions