6

Could anyone help me with a regex for a password with the following please.

include at least two of the following:

a lowercase letter
a capital letter
a number
a 'special character' (e.g. £, $, &, #)

Rui Jarimba
  • 11,166
  • 11
  • 56
  • 86
John Banks
  • 63
  • 2
  • *at least two of the following*... means that a password with two lowercase letters and two capital letters is valid (without numbers, etc.) is valid? – Oscar Mederos Mar 01 '13 at 20:54
  • Look [here](http://stackoverflow.com/questions/2394092/regex-for-strong-password?rq=1) or [here](http://stackoverflow.com/questions/1254952/regular-expression-for-password?rq=1) or maybe even [here](http://stackoverflow.com/questions/2370015/regular-expression-for-password-validation?rq=1). – Till Helge Mar 01 '13 at 20:55
  • Sorry, the password should contain 2 of the 4 character groups i.e. a lowercase letter and a number or a capital letter and a number etc – John Banks Mar 01 '13 at 20:56
  • 1
    A regex probably isn't the right tool for this job. The best regex I can think of for that would be an alternation of 12 distinct possibilities: lowercase followed by uppercase, uppercase followed by lowercase, lowercase followed by number, etc. And you have to define what a "special character" is. It would be easier to write some code to loop over the characters of the password and keep counts of each class. – Keith Thompson Mar 01 '13 at 20:58
  • 2
    @JohnBanks What programming language are you using? – Oscar Mederos Mar 01 '13 at 20:58
  • @Oscar .Net 4 MVC - I have this working sort of in js (?=.*\d)(?=.*[A-Z])|(?=.*\d)(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])|(?=.*[A-Z])(?=.*[a-z])|(?=.*[A-Z])(?=.*[^A-Za-z0-9])|(?=.*[a-z])(?=.*[^A-Za-z0-9])^.* but fails in mvc regex attribute – John Banks Mar 01 '13 at 21:02
  • Though it's not regex, there's a javascript password strength algorithm at the bottom of this js that may be useful to display in the browser and/or convert to another language: https://github.com/nak5ive/Form.PasswordStrength/blob/master/Source/Form.PasswordStrength.js – Joshua Dwire Mar 01 '13 at 21:07
  • I don't think this question is a duplicate. The OP wants to have at least `2` of the `4` requirements! – Oscar Mederos Mar 01 '13 at 21:11

3 Answers3

4

The following should work:

^(?![a-z]*$|[A-Z]*$|\d*$|[\W_]*$).*$

Example: http://www.rubular.com/r/effCmvehdx

The negative lookahead at the beginning will cause this to fail if the entire string is composed entirely of just one group.

Note that even though this fits your requirements, this is not a very good regex for a strong password. You probably also want a length check and you may want to require at least three of those groups instead of two.

Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • hmm.. am I missing something here? *include at least two of the following*... it means that `abcABC` or `abc123` have to be valid. – Oscar Mederos Mar 01 '13 at 21:09
  • @OscarMederos: Yes, and they are. Where's the problem? – Tim Pietzcker Mar 01 '13 at 21:16
  • I'm sorry. I was testing with Rad Software Regular Expression Designer, and it wasn't matching. I tested it with C# and worked. Could you edit your question so that I can remove my downvote? – Oscar Mederos Mar 01 '13 at 21:23
1

As Keith Thompson said in a comment, I don't think a single regex is worth here.

The following code will do what you want, and I think it is more readable, maintainable and easier to prove the correctness than a single regular expression:

string password = "123abc";
string[] regexes = new[]
    {
        "[a-z]", //any lowercase word
        "[A-Z]", //any uppercase word
        @"\d", //any digit
        @"\W" //special characters (or just [£$&#], adding the characters you want)
    };
bool isValid = regexes.Count(regex => Regex.IsMatch(password, regex)) >= 2; 
Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124
0

As I said in a comment, a regex is almost certainly not the right tool for this job. It's going to be much easier to write some code that iterates over the characters of the password, counting the number of characters in each class.

You haven't defined what a "special character" is. I'll assume that it means any character other than a letter or digit (which would include spaces and control characters). I'm also assuming that "letters" refers to just the 26 letters of the English alphabet -- which means that a non-English letter like ñ is a special character.

To take a simpler example, regexes aren't very good at expressing things like "foo and bar in either order"; you have to specify both order explicitly:

 foo.*bar|bar.*foo

In this case, you need 12 different choices. I think this is correct, but I haven't tested it.

[a-z].*[A-Z}|[A-Z].*[a-z}|[a-z].*[0-9]|[0-9].*[a-z]|[a-z].*[^a-zA-Z0-9]|[^a-zA-Z0-9].*[a-z]|[A-Z].*[0-9]|[0-9].*[A-Z]|[A-Z].*[^a-zA-Z0-9]|[^a-zA-Z0-9].*[A-Z]|[0-9].*[^a-zA-Z0-9]|[^a-zA-Z0-9].*[0-9]

This is an egrep-style or Perl-style regex. grep doesn't recognize | by default; if you need a grep-style regexp, replace each | by \|.

And if the requirements change, say requiring at least 3 out of 5 classes of characters, you'll need to completely rewrite the regex; you can't just tweak it.

Note that your requirements still permit Aa.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631