I'd avoid the issue of using a single regular expression, and simply combine the simple regular expressions together into an array, test the entered-password against that array of expressions using Array.prototype.filter()
to create a new array from those matches where the individual regular expressions test true (using RegExp.prototype.test()
):
function validateConditions (string, n) {
// individual tests:
var capital = /[A-Z]/, // any letter, from the characters A-Z (inclusive)
lower = /[a-z]/, // any letter, from the characters a-z (inclusive)
numeric = /\d/, // any number character
special = /[!*?$%&]/, // any of these special characters
// an array of those simple tests:
tests = [capital, lower, numeric, special],
// filtering the array of tests (to create a new array 'success'):
success = tests.filter(function (validate) {
// if the string tests true (RegExp.test returns a Boolean value):
if (validate.test(string)) {
// we return true (though any value would be fine, since
// we're only checking the length of the 'success' array):
return true;
}
});
// making sure that the 'success' array has a length equal to, or greater
// than the required number ('n') of matches:
return success.length >= n;
}
// adding an event-listener to the 'test' element, which runs on 'keyup':
document.getElementById('test').addEventListener('keyup', function (e) {
// logging the returned Boolean of validateConditions():
console.log(validateConditions(e.target.value, 3));
});
JS Fiddle demo.
References: