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:
- Coding without regex would be more efficient.
- A lookahead is NOT sinificantly expensive compared to the cost of using regex on its own.
And that this solution may be even more expensive than using a lookahead.
Description
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)|(?!))|(?!))|(?!))
Regex
\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)|(?!))|(?!))|(?!))
regex101 demo