3

I have an input string which is considered valid only if it contains:

  • At least one character in [a-z]
  • At least one integer in [0-9], and
  • At least one character in [A-Z]

There is no constraint on the order of occurrence of any of the above. How can I write a single regular expression that validates my input string ?

unni
  • 2,891
  • 4
  • 19
  • 22
  • possible duplicate of [Regexp Java for password validation](http://stackoverflow.com/questions/3802192/regexp-java-for-password-validation) – Tomalak Dec 05 '11 at 10:39
  • Don't just assume that regular expressions are the solution. In this case, they're inefficient and less obvious than @eumiro's solution. – Chris Morgan Dec 05 '11 at 10:46
  • @Chris Morgan: What do you mean by "inefficient" in this context? – Tomalak Dec 05 '11 at 10:51
  • @Tomalak how does the performance differ? – unni Dec 05 '11 at 11:09
  • @ChrisMorgan How does perfomance affect a password complexity check? We're talking about microsecond diffences at best, this ist not an argument. – Tomalak Dec 05 '11 at 11:39
  • I'm stating that it's slower. It is. It is exceedingly rare that such micro-performance will matter, but very occasionally it does. I would care much more about how obvious the code is: a non-regular expression solution is generally going to be more obvious (though @stema's answer, using the verbose mode, is good, too) – Chris Morgan Dec 05 '11 at 12:16

2 Answers2

5

Try this

^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$

See it here online on Regexr

The ^ and $ are anchors which bind the pattern to the start and the end of the string.

The (?=...) are lookahead assertions. they check if the pattern after the = is ahead but they don't match it. So to match something there needs to be a real pattern also. Here it is the .* at the end.
The .* would match the empty string also, but as soon as one of the lookaheads fail, the complete expression will fail.

For those who are concerned about the readability and maintainability, use the re.X modifier to allow pretty and commented regexes:

reg = re.compile(r'''
                ^            # Match the start of the string
                (?=.*[a-z])  # Check if there is a lowercase letter in the string
                (?=.*[A-Z])  # Check if there is a uppercase letter in the string
                (?=.*[0-9])  # Check if there is a digit in the string
                .*           # Match the string
                $            # Match the end of the string
                '''
                , re.X)      # eXtented option whitespace is not part of he pattern for better readability
stema
  • 90,351
  • 20
  • 107
  • 135
  • @unni I added a very readable implementation of the regex using the `re.X` option. I would recommend to use this style to keep the readability. – stema Dec 05 '11 at 11:05
  • You don't need the `^` and `.*$` bits. The assertions will do fine by themselves. – Chris Morgan Dec 05 '11 at 12:20
5

Do you need regular expression?

import string

if any(c in string.uppercase for c in t) and any(c in string.lowercase for c in t) and any(c in string.digits for c in t):

or an improved version of @YuvalAdam's improvement:

if all(any(c in x for c in t) for x in (string.uppercase, string.lowercase, string.digits)):
eumiro
  • 207,213
  • 34
  • 299
  • 261