I currently use this regular expression to check if a string conforms to a few conditions.
The conditions are string must be between 8 and 15 characters long. string must contain at least one number. string must contain at least one uppercase letter. string must contain at least one lowercase letter.
(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,15})$
It works for the most part, but it does not allow special character. Any help modifying this regex to allow special character is much appreciated.
I would check them one-by-one; i.e. look for a number \d+
, then if that fails you can tell the user they need to add a digit. This avoids returning an "Invalid" error without hinting to the user whats wrong with it.
Is a regular expression an easier/better way to enforce a simple constraint than the more obvious way?
static bool ValidatePassword( string password )
{
const int MIN_LENGTH = 8 ;
const int MAX_LENGTH = 15 ;
if ( password == null ) throw new ArgumentNullException() ;
bool meetsLengthRequirements = password.Length >= MIN_LENGTH && password.Length <= MAX_LENGTH ;
bool hasUpperCaseLetter = false ;
bool hasLowerCaseLetter = false ;
bool hasDecimalDigit = false ;
if ( meetsLengthRequirements )
{
foreach (char c in password )
{
if ( char.IsUpper(c) ) hasUpperCaseLetter = true ;
else if ( char.IsLower(c) ) hasLowerCaseLetter = true ;
else if ( char.IsDigit(c) ) hasDecimalDigit = true ;
}
}
bool isValid = meetsLengthRequirements
&& hasUpperCaseLetter
&& hasLowerCaseLetter
&& hasDecimalDigit
;
return isValid ;
}
Which do you think that maintenance programmer 3 years from now who needs to modify the constraint will have an easier time understanding?
Try this ( also corrected check for upper case and lower case, it had a bug since you grouped them as [a-zA-Z] it only looks for atleast one lower or upper. So separated them out ):
(?!^[0-9]*$)(?!^[a-z]*$)(?!^[A-Z]*$)^(.{8,15})$
Update: I found that the regex doesn't really work as expected and this is not how it is supposed to be written too!
Try something like this:
(?=^.{8,15}$)(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?!.*\s).*$
(Between 8 and 15 inclusive, contains atleast one digit, atleast one upper case and atleast one lower case and no whitespace.)
And I think this is easier to understand as well.
You may try this method:
private bool ValidatePassword(string password, out string ErrorMessage)
{
var input = password;
ErrorMessage = string.Empty;
if (string.IsNullOrWhiteSpace(input))
{
throw new Exception("Password should not be empty");
}
var hasNumber = new Regex(@"[0-9]+");
var hasUpperChar = new Regex(@"[A-Z]+");
var hasMiniMaxChars = new Regex(@".{8,15}");
var hasLowerChar = new Regex(@"[a-z]+");
var hasSymbols = new Regex(@"[!@#$%^&*()_+=\[{\]};:<>|./?,-]");
if (!hasLowerChar.IsMatch(input))
{
ErrorMessage = "Password should contain at least one lower case letter.";
return false;
}
else if (!hasUpperChar.IsMatch(input))
{
ErrorMessage = "Password should contain at least one upper case letter.";
return false;
}
else if (!hasMiniMaxChars.IsMatch(input))
{
ErrorMessage = "Password should not be lesser than 8 or greater than 15 characters.";
return false;
}
else if (!hasNumber.IsMatch(input))
{
ErrorMessage = "Password should contain at least one numeric value.";
return false;
}
else if (!hasSymbols.IsMatch(input))
{
ErrorMessage = "Password should contain at least one special case character.";
return false;
}
else
{
return true;
}
}
Thanks Nicholas Carey. I was going to use regex first but what you wrote changed my mind. It is so much easier to maintain this way.
//You can set these from your custom service methods
int minLen = 8;
int minDigit 2;
int minSpChar 2;
Boolean ErrorFlag = false;
//Check for password length
if (model.NewPassword.Length < minLen)
{
ErrorFlag = true;
ModelState.AddModelError("NewPassword", "Password must be at least " + minLen + " characters long.");
}
//Check for Digits and Special Characters
int digitCount = 0;
int splCharCount = 0;
foreach (char c in model.NewPassword)
{
if (char.IsDigit(c)) digitCount++;
if (Regex.IsMatch(c.ToString(), @"[!#$%&'()*+,-.:;<=>?@[\\\]{}^_`|~]")) splCharCount++;
}
if (digitCount < minDigit)
{
ErrorFlag = true;
ModelState.AddModelError("NewPassword", "Password must have at least " + minDigit + " digit(s).");
}
if (splCharCount < minSpChar)
{
ErrorFlag = true;
ModelState.AddModelError("NewPassword", "Password must have at least " + minSpChar + " special character(s).");
}
if (ErrorFlag)
return View(model);
Pattern satisfy, these below criteria
^(?!.*([A-Za-z0-9]))(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,15}$
Update to Justin answer above. if you want to use it using Data Annotation in MVC you can do as follow
[RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,15}$", ErrorMessage = "Password must be between 6 and 20 characters and contain one uppercase letter, one lowercase letter, one digit and one special character.")]
Long, and could maybe be shortened. Supports special characters ?"-_
.
\A(?=[-\?\"_a-zA-Z0-9]*?[A-Z])(?=[-\?\"_a-zA-Z0-9]*?[a-z])(?=[-\?\"_a-zA-Z0-9]*?[0-9])[-\?\"_a-zA-Z0-9]{8,15}\z
Source: Stackoverflow.com