tags:

views:

46

answers:

3

I need to create a regular expression to match strings that satisfy any two of the following three criteria: at least one upper case letter, at lease one lower case letter, at least one number.

for example the following would be the result:

"TestString" = MATCH (upper & lower)
"TestSTring5" = MATCH (upper, lower, & number)
"teststring" = NO MATCH (lower)
"TESTSTRING" = NO MATCH (upper)
"teststring5" = MATCH (lower & number)
"345T" = MATCH (number & upper)
A: 

It will be more straightforward and easier to maintain if you create a separate regex for each condition.

pseudocode:

reHasUpper = /[A-Z]/ ;
reHasLower = /[a-z]/ ;
reHasNumber = /[0-9]/ ;

function validatePassword (pwd) {

  metRequirements=0;

  if (reHasUpper.test(pwd)) metRequirements++;
  if (reHasLower.test(pwd)) metRequirements++;
  if (reHasNumber.test(pwd)) metRequirements++;

  return metRequirements > 1;

}
no
I agree, but I need to put it all into one RegEx.
Sako73
May I ask why? The resulting regex should be quite an abomination.
no
May guess would be that there is a simple validation engine that takes a regex pattern as parameter
seanizer
But the question is, what can you do with it? Can you access the backreferences? Can you apply it multiple times? `/([A-Z])|([a-z])|([0-9])/g` could do the trick if you can programatically check the backreferences.
no
A: 

That will be a huge regular expression.

You need to test for something like this (indented for readability only):

"[a-z].*[A-Z]|" +
"[A-Z].*[a-z]|" +
"[A-Z].*[0-9]|" +
"[0-9].*[A-Z]|" +
"[a-z].*[0-9]|" +
"[0-9].*[a-z]"
seanizer
What happens when the client decides the password also needs to have at least one symbol and be in unicode range U+0021-U+007E before it's valid? Your regex just got a lot longer ;)
no
Unfortunately, this is what the requirement is, and I did not include it for simplicity sake, but the symbols already are a requirement. I wasn't sure if there was a way of using lookahead groups to condense it, or if I did have to do it this way. Thanks for the help.
Sako73
A: 

I would try something along the lines of:

([a-z][A-Z]|[A-Z][a-z]|[a-z][0-9]|[0-9][a-z]|[A-Z][0-9]|[0-9][A-z])

What this essentially does is check for any pairs along the lines of:

  • a1
  • 1a
  • A1
  • 1A
  • aA
  • Aa

Within your string. If none of those pairs match, it fails. Since you're looking for any two of the three criteria to be met, this works by looking for pairs of characters that match the criteria.

Joshua Rodgers
I would note that this is simpler than other solutions because this relies on the fact that the match can occur anywhere inside a string. So when you consider your three criteria and the fact that only two of the three need to exist in the string and the fact that the transition from one criteria to the other occurs at a distinct boundary within the string . However this does not match on any strings that contain special characters like _ and @ outside of your specification.
Joshua Rodgers