views:

54

answers:

6

Hi,

I have to validate the password using regex. The password rule is like at least 1 uppercase and at least 2 numeric.

It works fine except if the character comes at the end of the string.

The regular expression which i am using is

"^(?=.*\d.{2})(?=.*[A-Z].{1})(?=.*[@#$%^&+=].{2}).{8,12}$"

Rules:

  • minimum length = 8
  • minimum uppercase = 1
  • minimum numeric = 2
  • minimum special character = 1

It works for Test123$$, Test$123, TEST123$s, Test123$1, Test12$3 but it fails if the character specified comes at the end of the string like Test123$, Test$a12, Test12aa@, 123aa@@T.

Please let me know if there is any fix for this.

A: 

Your list of requirements does not specify a regular language. Thus it will be difficult (if not impossible) to match using a regular expression.

VeeArr
+2  A: 

In your regex I see some problems:

  • (?=.*\d.{2}) - why the second ., you can't check for two occurrences with {2}, because that assumes that they are nearby ... Test1$2$3 should be allowed, too ...
  • (?=.*[A-Z].{1}) - why the second .
  • (?=.*[@#$%^&+=].{2}) - and again, why the second ., why do you check for 2 occurrences? Spec says one special char.
  • (And you check for a maximum of 12 chars, what is not specified, too)

Try

"^(?=.*\d.*\d)(?=.*[A-Z])(?=.*[@#$%^&+=]).{8,12}$"

which passes:

Debug.Assert( regex.IsMatch( "Test123$" ) );
Debug.Assert( regex.IsMatch( "Test123$$" ) );
Debug.Assert( regex.IsMatch( "$Test1$2" ) );   // two numbers, not following
Debug.Assert( regex.IsMatch( "Test$123" ) );
Debug.Assert( !regex.IsMatch( "Test12$" ) );   // 7 chars
Debug.Assert( !regex.IsMatch( "Test12345" ) ); // no special char
Debug.Assert( !regex.IsMatch( "Test$$$$" ) );  // no number
Debug.Assert( !regex.IsMatch( "Test$3$$" ) );  // only one number
Debug.Assert( !regex.IsMatch( "test12$$" ) );  // no upper case
tanascius
Why are you using `{1}` quantifier?
SilentGhost
@SilentGhost - exactly what I was going to ask.
GalacticCowboy
tanascius
+1  A: 

Your problem is that you use (atom).{length} and length is applied to ., not to atom. You should use (atom){length}. And, secondly, \d{2} is not «minimum numeric: 2». It is «2 consequent digits». «Minimum numeric: 2» looks like this: .*\d.*\d, so the full regex (note that (atom){1} and (atom) are the same regexes):

^(?=.*\d.*\d)(?=.*[A-Z])(?=.*[@#$%\^&+=]).{8,12}$

And, please, replace {8,12} with {8,}: you should not forbid users to enter long passwords.

ZyX
Except where "long" means that it causes other issues. But yeah, there's no reason not to allow a 20-30 character password. If you're properly salting/hashing your passwords, length should not be an issue anyway.
GalacticCowboy
A: 

Thanks for your answer, i will try solution. I really appreciate your time.

Kesavan
Please do not post such "answers" - normally you write comments instead ... if you like any answer, please upvote it - and you can accept the answer you prefer most.
tanascius
A: 

you cannot make a finite state machine for this, so (unless there's something different about regexes in practice than in theory) you won't be able to find a regex for this.

mainly, because it involves counting, which requires "memory" which is something a finite state machine doesn't have.

edit: apparently, there have been advances in DFA "technology". see comments to this post.

zaphod
Many flavors of regex support the concepts of "backtracking" and "zero-width assertions", which are precisely what the OP wants. The FSA is more complex, but it's not impossible.
GalacticCowboy
See this question: http://stackoverflow.com/questions/2974210/does-lookaround-affect-which-languages-can-be-matched-by-regular-expressions.
ZyX
thank you both. i'll look more into it.
zaphod
A: 

While you're not saying what flavour of regex you're using, I'd suggest the following approach, which —if not most efficient— is more readable and maintainable (using Python only for example):

>>> import string
>>> def valid(s):
    return 8 <= len(s) <= 12 and \
           any(c in string.ascii_uppercase for c in s) and \
           sum(c in string.digits for c in s) >= 2 and \
           any(c in string.punctuation for c in s)

>>> valid('abcdefA')
False
>>> valid('123aa@@T')
True
>>> valid('Test123$')
True
>>> valid('Test123_')
True
SilentGhost