2

Say I have a regex that checks for alphanumeric.

I now want to create another regex that checks for at least 1 number in the password. And I want to check if it has at least 1 non-alphanumeric character (somethign other than a letter or number).

Should I just call each one seperatley, and if one fails return false or is there a way to combine them into 1 call?

mrblah
  • 99,669
  • 140
  • 310
  • 420

7 Answers7

3

Depends on exactly what criteria you're using, but it would probably be better to do a single pass through the string and set a number of flags based on what you've seen:

  • hasDigit
  • hasAlpha
  • hasSymbol
  • etc

Then use these at the end to decide if the password is complex enough.

Even Better:

As lexu suggests, using counts instead of flags would allow greater flexibility.

Draemon
  • 33,955
  • 16
  • 77
  • 104
  • 1
    I like the idea (and it answers the question asked!), but I would suggest counting Digits,Aplha,Symbol instead of setting a single flag each .. this enables the next step -> evaluating the PWD strength. – lexu Jul 20 '09 at 11:31
3

I would compose small methods using &&:

internal bool HasDigit(string password) { .. }
internal bool HasNonAlpha(string password) { .. }

bool IsStrong(string password) {  
   return HasDigit(password) && HasNonAlpha(password);
}   
dfa
  • 114,442
  • 31
  • 189
  • 228
2

I think this is what you're looking for:

^.{6,}(?<=\d.*)(?<=[^a-zA-Z0-9].*)$

(will match a password with a minimum length of 6, with at least one digit and one non-alphanumerical character)

In code:

public bool PasswordOk(string pwd) 
{
    return Regex.IsMatch(pwd,@"^.{6,}(?<=\d.*)(?<=[^a-zA-Z0-9].*)$");
}
Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223
1

You should use two calls. For a bit more advanced testing you can use The password meter. It is freely available for distribution under GPL.

Andrea Ambu
  • 38,188
  • 14
  • 54
  • 77
1

IMHO, it's a question of style whether to make one or two statements from it.

Why not check for it in any of the two orders that they may appear. (As regular expressions go, we don't have something like a counter for braces or parantheses, thus we have to honor the possible ordering of things.

That one might work for perl:

(\d.*[^[:alnum:]])|([^[:alnum:]].*\d)

Might be easier to read to make two statements from it, especially because then every semantical condition is only occurring once.

Don Johe
  • 989
  • 2
  • 12
  • 24
  • Hey, look: somebody actually answered the question. There ought to be more upvotes. – Jeremy Stein Jul 20 '09 at 19:36
  • Actually this is not strictly an answer (because it is not C#), but I think regexps everywhere are mostly perl-syntax. (At least you stumble upon "see perl regexp doc for details" every now and then.) – Don Johe Jul 21 '09 at 06:29
0

You add an | (or) operator into the regex e.g.

[0-9]|[A-Z]

James
  • 80,725
  • 18
  • 167
  • 237
  • True, however I always feel its nicer to use the | to split them up so it is clearer what is going on – James Jul 20 '09 at 11:06
  • 1
    Actually this statement wouldn't work because it is not implementing the required AND. This regexp fires if a capital letter OR a numerical is present. Requested has been "one or more digits AND one or more non-alphanumericals". – Don Johe Jul 20 '09 at 11:15
  • He already has the regexes, he wanted to know how to use 2 regexes in the one statement... – James Jul 20 '09 at 11:24
  • @James, that's faulty thinking on both counts. `[0-9]|[A-Z]` may seem clearer than `[0-9A-Z]` to you, but it's also much less efficient. (It won't matter in this case, but the difference can be dramatic.) And, as Don Johe said, you need to AND the regexes, not OR them. That usually calls for lookaheads: `(?=.*[0-9])(?=.*[A-Z])` etc. (This has been rehashed dozens of times; just search for "password regex".) – Alan Moore Jul 20 '09 at 13:05
  • I think I misunderstood the question then, I assumed he had 2 regexes and wanted to test if the string matched either or. – James Jul 20 '09 at 14:00
0

Regex is not the fastest way.

Give this a try:

string Password = "Pass12!";

bool ValidPassword = Password.Any(char.IsDigit)
    && !Password.All(char.IsLetterOrDigit)
    && Password.Length >= 6;

Instead of:

string Password = "Pass12!";

bool ValidPassword = Regex.IsMatch(Password, @"^.{6,}(?<=\d.*)(?<=[^a-zA-Z0-9].*)$");

I you iterate through it 1 million times it will take the first 157ms and the second 1251ms.

And the most important thing the others said already: much better to maintain.

Bart Vanseer
  • 348
  • 3
  • 6