开发者

How to add a whitelist of characters to a positive look ahead regex

I am using the following regex to validate my password strength.

^(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*[0-9]{1,})(?=.*[@\#\$%\^&\+=!\?\*]{1,}).{8,12}$

8-12 chars, at least 1 lower case, 1 uppercase, 1 number, and 1 special char from the approved list. (I know that I can't just set {1,4} in the look ahead an开发者_运维问答d have it work correctly, but I am hoping to resolve that soon, so I left it the way it is.)

The expression seems a little verbose, but my users can set their own password rules, this seemed like the best way to create interchangeable parts in the regular expression.

To this I want to add that all characters must be in the set

[A-Z]|[a-z]|[0-9]|[@\#\$%\^&\+=!\?\*]

If any characters are not in that set the line should not match.

Unfortunately, I'm not finding the correct way to express this. Any help is much appreciated.

I'm using the .net implementation if that is relevant to the discussion.


You could use a negative look-around to have the match fail in case a anything not defined in the set is found.

First, group all the characters into one class and specify that you want to match anything not in this class by using a caret at the beginning:

[^A-Za-z0-9@\#\$%\^&\+=!\?\*]

Next, update the pattern with this negative character class and a negative look-around:

@"^(?!.*[^A-Za-z0-9@\#\$%\^&\+=!\?\*])(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*[0-9]{1,})(?=.*[@\#\$%\^&\+=!\?\*]{1,}).{8,12}$"

Also, you usually don't need to escape metacharacters within a character class, so you could further clean up the pattern by removing the escapes. That would shorten the pattern to this:

@"^(?!.*[^A-Za-z0-9@#$%^&+=!?*])(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*[0-9]{1,})(?=.*[@#$%^&+=!?*]{1,}).{8,12}$"

Of course if you allow a dash be sure to escape it or place it at the start or end of a character class to avoid accidentally specifying a range of characters. This is important if your users can supply the pattern info, in which case you might want to use the Regex.Escape method on any user supplied input.


I don't see why you're using regex in this way. Passwords don't follow a pattern, they follow a set of rules. Instead of trying to match it to a pattern, check it against a set of rules:

Psuedo-code:

function checkPassword(password, rules)
{
  for (i = 0; i < rules.length; i++)
  {
    if ( !rules[i]( password ) ) return false;
  }
  return true;
}

function hasCapital(password)
{
  return password.matches(/[A-Z]/);
}
function hasLower(password)
{
  return password.matches(/[a-z]/);
}
function hasNumber(password)
{
  return password.matches(/[0-9]/);
}
function hasSpecial(password)
{
  return password.matches(/[@\#\$%\^&\+=!\?\*]/);
}

password = getPassword();
passwordIsValid = false;
rules = [];
rules[] = hasCapital;
rules[] = hasLower;
rules[] = hasNumber;
rules[] = hasSpecial;

passwordIsValid = checkPassword( password, rules );

This format is modular, you can specify whatever rules you want, and it will let you know if any have been broken. Additionally, you'll notice that the actual RegEx used makes sence, and is therefor debuggable.

If you're using RegEx it should simplify your code, not make it more difficult to understand.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜