8

I need a regular expression for a password. The password has to contain at least 8 characters. At least one character must be a number or a special character (not a letter).

[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 8)]
[RegularExpression(@"(?=.*\W)?(?=.*\d)", ErrorMessage = "Error message")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }

I have a length validation, but I need help with a regular expression that checks if the password contains at least one number or special character.

Examples of valid passwords:

testtest85*
testtes*
testtes1
test1234*+

Examples of not valid passwords:

testtest
testabc
Toto
  • 89,455
  • 62
  • 89
  • 125
cashmere
  • 885
  • 3
  • 12
  • 37
  • 3
    What makes a character special for you? – Joey Aug 21 '12 at 12:40
  • What language is that? There may be different regex flavours. – Bergi Aug 21 '12 at 12:41
  • Why do you use lookahead? Also, lookarounds cannot be optional. – Bergi Aug 21 '12 at 12:42
  • 3
    @Bergi: This looks like C# in ASP.NET MVC – Daniel Hilgarth Aug 21 '12 at 12:42
  • 1
    @cashmere - `etc` is not helpful, by `etc` do you mean `; , " ' ? < > { } & ^ % $ # @ ! * . / \ - + = ~ , ` could this list also include non printable characters? What about high order characters that require multiple key strokes to enter (my password generator will create those if asked)? – pstrjds Aug 21 '12 at 12:47
  • Do you know that the password can be all numbers with your rules? `12345678` is a perfect password with your ruleset which is far weaker than anything. – Sedat Kapanoglu Nov 09 '17 at 09:02
  • I assume/believe, by *special character* the OP means any *non-letter character*. – Ωmega Nov 10 '17 at 14:15

6 Answers6

28

Use regex pattern ^(?=.{8})(?=.*[^a-zA-Z])


Explanation:

^(?=.{8})(?=.*[^a-zA-Z])
│└──┬───┘└──────┬──────┘
│   │           │
│   │           └ string contains some non-letter character
│   │
│   └ string contains at least 8 characters
│
└ begining of line/string

If you want to limit also maximum length (let's say 16), then use regex pattern:

^(?=.{8,16}$)(?=.*[^a-zA-Z])
Ωmega
  • 42,614
  • 34
  • 134
  • 203
2

Run it through a fairly simple regex: [^a-zA-Z]

And then check it's length separately:

if(string.Length > 7)
J V
  • 11,402
  • 10
  • 52
  • 72
  • 3
    The `StringLength(..., MinimumLength = 8)` attribute that's already in the question *should* suffice to enforce a minimum length, so there shouldn't be a need to explicitly re-check (though it can't hurt, I suppose). –  Aug 21 '12 at 12:55
  • I try your regex, but it does not work [link](http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx). I have validation for length. – cashmere Aug 21 '12 at 13:26
  • On that link it works fine, it's returning the spaces and periods it matched. If you just type in "Lorem" it will return "Found 0 matches". Look at it on [regexpal](http://regexpal.com) - it highlights the matches on the fly – J V Aug 21 '12 at 13:28
  • @JV regexpal uses JavaScript regexes, not .NET regexes. But as you mention, on cashmere's link, it works too. –  Aug 21 '12 at 13:50
  • `[^a-zA-Z]` could also be replaced with `[\W0-9]` to not count non-english letters as special – Martin Brenden Aug 22 '12 at 12:47
1

A simple method will be like this:

Match match1 = Regex.Match(<input_string>, @"(?=.{7})");   

match1.Success ensures that there are at least 8 characters.

Match match2 = Regex.Match(<input_string>, [^a-zA-Z]);

match2.Success ensures that there is at least one special character or number within the string.

So, match1.Success && match2.Success guarantees will get what you want.
Johnny
  • 29
  • 3
0

I tried Omega's example however it was not working with my C# code. I recommend using this instead:

[RegularExpression(@"^(?=[^\d_].*?\d)\w(\w|[!@#$%]){7,20}", ErrorMessage = @"Error. Password must have one capital, one special character and one numerical character. It can not start with a special character or a digit.")]
cyclical
  • 395
  • 4
  • 14
-1

An expression like this:

[a-zA-Z]*[0-9\+\*][a-zA-Z0-9\+\*]*

should work just fine (obviously insert any additional special characters you want to allow or use ^ operator to match anything except letters/numbers); no need to use complicated lookarounds. This approach makes sense if you only want to allow a certain subset of special characters that you know are "safe", and disallow all others.

If you want to include all special characters except certain ones which you know are "unsafe", then it makes sense to use something like:

\w[^\\]*[^a-zA-Z\\][^\\]*

In this case, you are explicitly disallowing backslashes in your password and allowing any combination with at least one non-alphabetic character otherwise.

The expression above will match any string containing letters and at least one number or +,*. As for the "length of 8" requirement, theres really no reason to check that using regex.

Moritz
  • 4,565
  • 2
  • 23
  • 21
  • 2
    If you list the allowed characters in passwords, you're preventing me from using more secure passwords. You should look at it the other way around (as in J V's answer): if *any* character is *not* a letter, then the password passes the check. –  Aug 21 '12 at 12:51
  • Word. Edited to reflect this. Also, I think J V's answer is probably better in this situation anyways. I was trying to think of a regex that would match the whole password if valid, but that isn't really necessary. I guess its enough here to just check if any part of the password is not alphabetic, as J V suggested. – Moritz Aug 21 '12 at 13:05
-1
  function randomPassword(length) {
        var chars = "abcdefghijklmnopqrstuvwxyz#$%ABCDEFGHIJKLMNOP1234567890";
        var pass = "";
        for (var x = 0; x < length; x++) {
            var i = Math.floor(Math.random() * chars.length);
            pass += chars.charAt(i);
        }
        var pattern = false;
        var passwordpattern = new RegExp("[^a-zA-Z0-9+]+[0-9+]+[A-Z+]+[a-z+]");
        pattern = passwordpattern.test(pass);
        if (pattern == true)
            { alert(pass); }
        else
         { randomPassword(length); }
    }

try this to create the random password with atleast one special character

Abi
  • 69
  • 1
  • 2