简体   繁体   中英

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

I've been Googling a lot and I didn't find an answer for my question:

How can I check with a regular expression whether a string contains at least one of each of these:

  • Uppercase letter
  • Lowercase letter
  • Digit
  • Special Character: ~`!@#$%^&*()-_=+\\|[{]};:'",<.>/?

So I need at least a capital letter and at least a small letter and at least a digit and at least a special character.

I'm sure the answer is very simple, but I can't find it. Any help is greatly appreciated.

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, eg

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

EDIT fixed quote marks - been doing too much damned JS programming...

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. eg Something like:

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

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!

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.

String regex = "^(?=.*?\\p{Lu})(?=.*?[\\p{L}&&[^\\p{Lu}]])(?=.*?\\d)" + 
               "(?=.*?[`~!@#$%^&*()\\-_=+\\\\\\|\\[{\\]};:'\",<.>/?]).*$"
  1. ^ This matches the beginning of the string. It's not strictly necessary for this to work, but I find it helps readability and understanding. Also, using it when you can often makes a big performance improvement and is almost never a penalty.

  2. (?= X ) This is called a positive lookahead. Basically what we're saying is "The beginning of the string (^) must be followed by this thing X in order for a match, but DO NOT advance the cursor to the end of X , stay at the beginning of the line. (that's the "look ahead" part.)

  3. .*?\\p{Lu} eat characters after the beginning of the line until you find a capital letter. This will fail to match if no capital letter is found. We use \\p{Lu} instead of AZ because we don't want people from other parts of the world to throw up their hands and complain about how our software was written by an ignorant American.

  4. Now we go back to the beginning of the line (we go back because we used lookahead) and start a search for .*?[\\p{L}&&[^\\p{Lu}]] shorthand for "all letters, minus the capitals" (hence matches lower case).

  5. .*?\\d + .*?[`~!@#$%^&*()\\-_=+\\\\\\|\\[{\\]};:'\\",<.>/?] repeat for digits and for your list of special characters.

  6. .*$ Match everything else until the end of the line. We do this just because of the semantics of the 'matches' methods in java that see if the entire string is a match for the regex. You could leave this part of and use the Matcher#find() method and get the same result.

  7. The Owl is one of the best books ever written on any technical subject. And it's short and fast to read. I cannot recommend it enough.

Because these will not appear in any particular order, you will need lookahead assertions for each required character class:

(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~!@#$%\^&*()\-_=+\|\[{\]};:'",<.>/?])

(NOTE: because backslash, caret, hyphen, and square brackets can be special inside a range, they should be backslash escaped if they appear in the range, as shown in the fourth lookahead assertion.)

This construct can be made considerably more readable using whitespace and comments, if your regex variant supports the x modifier. In java.util.regex , you can do:

(?x)         # extended syntax
(?=.*[A-Z])  # look ahead for at least one upper case
(?=.*[a-z])  # look ahead for at least one lower case
(?=.*[0-9])  # look ahead for at least one numeral
(?=.*[~!@#$%\^&*()\-_=+\|\[{\]};:'",<.>/?])
             # look ahead for at least one of the listed symbols

You're looking for character classes .

  • Big letter: [AZ]
  • Small letter: [az]
  • Digit: [0-9] or \\d
  • Special character: [^A-Za-z0-9] (That is, not any of the others, where ^ negates the class)

If you want to test for 'this' or 'that', you can combine those ranges. For example, Big or Small letters would be [A-Za-z] .

\\w : is used for matching alpha-numeric (alphabets can be either big or small)
\\W : is used for matching special characters

I think this RegEx will be helpful for you:

[\w|\W]+

Here's a good RegEx Simulator , you can use it for building your own RegEx.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM