0

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.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
Kesavan
  • 1
  • 1
  • Your regex works only for `Test$123`. – ZyX Jun 09 '10 at 16:50
  • What happens if you try 123$$Test? I suspect it will fail. I am not so sure using a regular expression is the best tool for this purpose. – whatsisname Jun 09 '10 at 16:50
  • @whatsisname in this case it is not the best, but it will work. Check my regex: your string successfully passes. – ZyX Jun 09 '10 at 16:53

5 Answers5

2

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
  • 53,078
  • 22
  • 114
  • 136
1

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
  • 52,536
  • 7
  • 114
  • 135
  • 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 Jun 09 '10 at 20:15
0

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
  • 6,039
  • 3
  • 24
  • 45
0

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.

badideas
  • 3,189
  • 3
  • 25
  • 26
  • 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 Jun 09 '10 at 17:35
  • See this question: http://stackoverflow.com/questions/2974210/does-lookaround-affect-which-languages-can-be-matched-by-regular-expressions. – ZyX Jun 09 '10 at 19:28
0

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
  • 307,395
  • 66
  • 306
  • 293