I'm a Regex newbie, and so far have only used it for simple things, like "must be a number or letter". Now I have to do something a bit more complex.
I need to use it to validate a password, which must be 8-16 characters, free of control/non-printing/non-ASCII characters, and must have at least three of the following:
I'm thinking what I have to do is write something like "one capital letter, lowercase letter and number, OR one capital letter, lowercase letter and one symbol, OR one capital letter, one number or one symbol, OR...." to cover all possible "3 out of 4" combinations, but that seems excessive. Is there a simpler solution?
The correct way to do this is to check all of the five conditions separately. However, I assume there is a reason you want a regex, here you go:
/^((?=.*[A-Z])(?=.*[a-z])(?=.*\d)|(?=.*[a-z])(?=.*\d)(?=.*[\$\%\&])|(?=.*[A-Z])(?=.*\d)(?=.*[\$\%\&])|(?=.*[A-Z])(?=.*[a-z])(?=.*[\$\%\&])).{8,16}$/
Explanation:
^$
.{n,m}
matches between n
and m
characters (8 and 16 in our case).(?=.*X)
, where X
is the thing you want to check. For example, if you want to make sure the string contains a lowercase letter you can do (?=.*[a-z])
.X
, Y
and Z
, but without actually matching them, you can use the previous recipe by appending the three lookaheads (?=.*X)(?=.*Y)(?=.*Z)
|
(or) - cCD|cDS|CDS|CcS
(c
= lowercase letter, C
= capital letter, D
= digit, S
= special)See it in action
The best way to do this is by checking each condition separately. Performance will suffer if you try to fit all conditional criteria into one expression (see the accepted answer). I also highly recommend against limiting the length of the password to 16 chars — this is extremely insecure for modern standards. Try something more like 64 chars, or even better, 128 — assuming your hashing architecture can handle the load.
You also didn't specify a language, but this is one way to do it in JavaScript:
var pws = [
"%5abCdefg",
"&5ab",
"%5abCdef",
"5Bcdwefg",
"BCADLKJSDSDFlk"
];
function pwCheck(pw) {
var criteria = 0;
if (pw.toUpperCase() != pw) {
// has lower case letters
criteria++;
}
if (pw.toLowerCase() != pw) {
// has upper case letters
criteria++;
}
if (/^[a-zA-Z0-9]*$/.test(pw) === false) {
// has special characters
criteria++;
}
if (/\d/.test(pw) === true) {
// has numbers
criteria++;
}
// returns true if 3 or more criteria was met and length is appropriate
return (criteria >= 3 && pw.length >= 8 && pw.length <= 16);
}
pws.forEach(function(pw) {
console.log(pw + ": " + pwCheck(pw).toString());
});
Not sure if its a iOS thing, the regex with "d" for digits [0-9] wasn't working as expected, example String that had issues = "AAAAAA1$"
The fix below works fine in Objective-C and Swift 3
^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])).{8,16}$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With