Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


public boolean isLegalPassword(String pass) {

     if (!pass.matches(".*[A-Z].*")) return false;

     if (!pass.matches(".*[a-z].*")) return false;

     if (!pass.matches(".*\\d.*")) return false;

     if (!pass.matches(".*[~!.......].*")) return false;

     return true;
}

@AlanMoore I gave you a +1 by error... It is true that .matches() is woefully misnamed regex-wise and expects to match the whole input, however the solution is not to use .* around. The real solution is to use .find() instead, which performs real regex matching.

@fge: Unfortunately, String doesn't have a find() method, and I don't see any point in telling people to use Pattern.compile("[A-Z]").matcher(pass).find()) when pass.matches(".*[A-Z].*") gets the job done. The only thing to watch out for is if there are line separator characters (\n, \r, etc.) in the string, and I don't think that's an issue here.

Regular expressions aren't very good for tests where you require all of several conditions to be met.

The simplest answer therefore is not to try and test them all at the same time, but just to try each of the four classes in turn.

Your code might be fractionally slower, but it'll be easier to read and maintain, e.g.

Note
Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


private static final Pattern [] passwordRegexes = new Pattern[4];
    {
        passwordRegexes[0] = Pattern.compile(".*[A-Z].*");
        passwordRegexes[1] = Pattern.compile(".*[a-z].*");
        passwordRegexes[2] = Pattern.compile(".*\\d.*");
        passwordRegexes[3] = Pattern.compile(".*[~!].*");
    }
    public boolean isLegalPassword(String pass) {

        for(int i = 0; i < passwordRegexes.length; i++){
            if(!passwordRegexes[i].matcher(pass).matches())
                return false;
        }
        return true;
    }

+1. It all depends on your requirements, doesn't it. Hardware limitations always factor in, and anybody who fails to consider them in their design will eventually pay the cost, whether it's as obvious as a three-day run time for a single SQL query taking your application down, or as subtle as having to buy a larger fractional colo three months sooner than you might have otherwise.

I agree that @Alnitak's answer is the easiest to read, however it suffers from the fact that it has to evaluate the regexs each time it's run. Since the regexs are fixed, it makes sense to compile them then compare against them. e.g. Something like:

When run 100,000 times on a 10 character password the above code was twice as fast. Although, I guess now you could say this code is harder to read! Never mind!

Note
Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


String regex = "^(?=.*?\\p{Lu})(?=.*?[\\p{L}&&[^\\p{Lu}]])(?=.*?\\d)" + 
               "(?=.*?[`~!@#$%^&*()\\-_=+\\\\\\|\\[{\\]};:'\",<.>/?]).*$"

+1 Thank you, Affe, can you explain this to me? I must confess that I'm not a regular expression expert and I just wanted to solve my problem with regular expressions, instead of checking my strings character-by-character.

This does what you want in java as a single regex, although I would personally use something like the solution provided by Mark Rhodes. This will get ridiculous quick (if it isn't already...) as the rules get more complicated.

Note
Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


String regex = "^(?=.*?\\p{Lu})(?=.*?[\\p{L}&&[^\\p{Lu}]])(?=.*?\\d)" + 
               "(?=.*?[`~!@#$%^&*()\\-_=+\\\\\\|\\[{\\]};:'\",<.>/?]).*$"

+1 Thank you, Affe, can you explain this to me? I must confess that I'm not a regular expression expert and I just wanted to solve my problem with regular expressions, instead of checking my strings character-by-character.

This does what you want in java as a single regex, although I would personally use something like the solution provided by Mark Rhodes. This will get ridiculous quick (if it isn't already...) as the rules get more complicated.

Note
Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


private static final Pattern [] passwordRegexes = new Pattern[4];
    {
        passwordRegexes[0] = Pattern.compile(".*[A-Z].*");
        passwordRegexes[1] = Pattern.compile(".*[a-z].*");
        passwordRegexes[2] = Pattern.compile(".*\\d.*");
        passwordRegexes[3] = Pattern.compile(".*[~!].*");
    }
    public boolean isLegalPassword(String pass) {

        for(int i = 0; i < passwordRegexes.length; i++){
            if(!passwordRegexes[i].matcher(pass).matches())
                return false;
        }
        return true;
    }

+1. It all depends on your requirements, doesn't it. Hardware limitations always factor in, and anybody who fails to consider them in their design will eventually pay the cost, whether it's as obvious as a three-day run time for a single SQL query taking your application down, or as subtle as having to buy a larger fractional colo three months sooner than you might have otherwise.

I agree that @Alnitak's answer is the easiest to read, however it suffers from the fact that it has to evaluate the regexs each time it's run. Since the regexs are fixed, it makes sense to compile them then compare against them. e.g. Something like:

When run 100,000 times on a 10 character password the above code was twice as fast. Although, I guess now you could say this code is harder to read! Never mind!

Note
Rectangle 27 0

java How to check whether a string contains lowercase letter, uppercase letter, special character and digit?


public boolean isLegalPassword(String pass) {

     if (!pass.matches(".*[A-Z].*")) return false;

     if (!pass.matches(".*[a-z].*")) return false;

     if (!pass.matches(".*\\d.*")) return false;

     if (!pass.matches(".*[~!.......].*")) return false;

     return true;
}

@AlanMoore I gave you a +1 by error... It is true that .matches() is woefully misnamed regex-wise and expects to match the whole input, however the solution is not to use .* around. The real solution is to use .find() instead, which performs real regex matching.

@fge: Unfortunately, String doesn't have a find() method, and I don't see any point in telling people to use Pattern.compile("[A-Z]").matcher(pass).find()) when pass.matches(".*[A-Z].*") gets the job done. The only thing to watch out for is if there are line separator characters (\n, \r, etc.) in the string, and I don't think that's an issue here.

Regular expressions aren't very good for tests where you require all of several conditions to be met.

The simplest answer therefore is not to try and test them all at the same time, but just to try each of the four classes in turn.

Your code might be fractionally slower, but it'll be easier to read and maintain, e.g.

Note