Regular expression to enforce complex passwords, matching 3 out of 4 rules

0 votes
asked Aug 12, 2010 by dagda1

I have the following criteria for creating a regular expression for a password that conforms to the following rules:

  1. The password must be 8 characters long (this I can do :-)).

The password must then contain characters from at least 3 of the following 4 rules:

  1. Upper case
  2. Lower case
  3. Numbers
  4. Non-alpha numeric

I can make the expression match ALL of those rules with the following expression:

/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.[\W]).{8,}$/

But I am struggling with how to do this in such a way that it only needs to solve any 3 of the 4 rules.

Can anyone help me out with this?

4 Answers

0 votes
answered Aug 12, 2010 by kennytm

Don't use one regex to check it then.

if (password.length < 8)
  alert("bad password");
var hasUpperCase = /[A-Z]/.test(password);
var hasLowerCase = /[a-z]/.test(password);
var hasNumbers = /\d/.test(password);
var hasNonalphas = /\W/.test(password);
if (hasUpperCase + hasLowerCase + hasNumbers + hasNonalphas < 3)
  alert("bad password");

If you must use a single regex:

^(?:(?=.*[a-z])(?:(?=.*[A-Z])(?=.*[\d\W])|(?=.*\W)(?=.*\d))|(?=.*\W)(?=.*[A-Z])(?=.*\d)).{8,}$

This regex is not optimized for efficiency. It is constructed by A·B·C + A·B·D + A·C·D + B·C·D with some factorization. Breakdown:

^
(?:
    (?=.*[a-z])       # 1. there is a lower-case letter ahead,
    (?:               #    and
        (?=.*[A-Z])   #     1.a.i) there is also an upper-case letter, and
        (?=.*[\d\W])  #     1.a.ii) a number (\d) or symbol (\W),
    |                 #    or
        (?=.*\W)      #     1.b.i) there is a symbol, and
        (?=.*\d)      #     1.b.ii) a number ahead
    )
|                     # OR
    (?=.*\W)          # 2.a) there is a symbol, and
    (?=.*[A-Z])       # 2.b) an upper-case letter, and
    (?=.*\d)          # 2.c) a number ahead.
)
.{8,}                 # the password must be at least 8 characters long.
$
0 votes
answered Aug 12, 2010 by scy

You could write a really sophisticated regex to do that. Instead, I’d suggest writing four distinct regexes, one for each rule, and testing them one by one, counting how many of them matched. If three out of four did, accept the password.

0 votes
answered Aug 12, 2010 by pauljwilliams

Id suggest doing the checks seperately, and then just totalling up how many match.

(I'd also not use a regex in any of them, but thats just my personal POV - namely that they hinder readability and are generally write-once code)

0 votes
answered Aug 18, 2012 by ajithparamban

You can use the following Regex:

(^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$)?(^(?=.*\d)(?=.*[a-z])(?=.*[@#$%^&+=]).*$)?(^(?=.*\d)(?=.*[A-Z])(?=.*[@#$%^&+=]).*$)?(^(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$)?

With a password minimum length of 8 and max length 32 you can use the following Regex:

(^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,32}$)?(^(?=.*\d)(?=.*[a-z])(?=.*[@#$%^&+=]).{8,32}$)?(^(?=.*\d)(?=.*[A-Z])(?=.*[@#$%^&+=]).{8,32}$)?(^(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).{8,32}$)?
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...