Reputation: 10514
I am looking for a regex that matches strings (i.e., passwords) that have at least 8 characters, at least one upper case character, at least one lower case character, and at least one number.
A regex that works (with the help of here) would be:
(^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$)
This regex uses positive lookahead (?=
). This is an expensive operation. Is it possible to make this regex without using positive lookahead?
Upvotes: 2
Views: 2583
Reputation: 6511
at least 8 characters, at least one upper case character, at least one lower case character, and at least one number
It is kind of like a puzzle
Ok, I'm going to take this as a puzzle, provided it's understood that:
And that this solution may be even more expensive than using a lookahead.
We can use a subpattern like
\A(?:[A-Z]|[a-z]|[0-9]|.){8,}
to check there are at least 8 characters in the subject, while providing the 4 options (uppercase, lowercase, digit, or some other character).
Then, we'll create a backreference for the first 3 required options:
\A(?:(?<upper>[A-Z])|(?<lower>[a-z])|(?<digit>[0-9])|.){8,}
And finally, we'll use an IF clause to check that each group was captured:
(?(upper) (?#check 2nd condition) | (?#make it fail) )
using (?!)
to make it fail if any of the conditions isn't met:
(?(upper)(?(lower)(?(digit)|(?!))|(?!))|(?!))
\A #beggining of string
(?> #MAIN iteration (atomic only for efficiency)
(?<upper>[A-Z]) # an uppercase letter
| # or
(?<lower>[a-z]) # a lowercase letter
| # or
(?<digit>[0-9]) # a digit
| # or
. # anything else
){8,}? #REPEATED 8+ times
#
#CONDITIONS:
(?(upper) # 1. There must be at least 1 uppercase
(?(lower) # 2. If (1), there must be 1 lowercase
(?(digit) # 3. If (2), there must be 1 digit
| (?!) # Else fail
) #
| (?!) # Else fail
) #
| (?!) # Else fail
) #
One-liner:
\A(?>(?<upper>[A-Z])|(?<lower>[a-z])|(?<digit>[0-9])|.){8,}?(?(upper)(?(lower)(?(digit)|(?!))|(?!))|(?!))
Upvotes: 2