问题
In password strategy, there are 4 requirements. It should contains any three of the following
- lower case.
- upper case.
- numeric.
- special character.
The following regex will match all cases
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{4,8}$
I know I can use '|' to declare all combinations, however, that will produce a supper long regex. What is the best way to replace '|' so that it can check if the input contains any of three conditions in the combination?
回答1:
If you're using a PCRE flavor, the following one could suit your needs (formatted for readability):
^(?:
((?=.*\d))((?=.*[a-z]))((?=.*[A-Z]))((?=.*[^a-zA-Z0-9]))|
(?1) (?2) (?3) |
(?1) (?2) (?4) |
(?1) (?3) (?4) |
(?2) (?3) (?4)
).{4,8}$

One-lined:
^(?:((?=.*\d))((?=.*[a-z]))((?=.*[A-Z]))((?=.*[^a-zA-Z0-9]))|(?1)(?2)(?3)|(?1)(?2)(?4)|(?1)(?3)(?4)|(?2)(?3)(?4)).{4,8}$
Demo on Debuggex
JavaScript regex flavor does not support recursion (it does not support many things actually). Better use 4 different regexes instead, for example:
var validate = function(input) {
var regexes = [
"[A-Z]",
"[a-z]",
"[0-9]",
"[^a-zA-Z0-9]"
];
var count = 0;
for (var i = 0, n = regexes.length; i < n; i++) {
if (input.match(regexes[i])) {
count++;
}
}
return count >=3 && input.match("^.{4,8}$");
};
回答2:
Sure, here's a method which uses a slight modification of the same regex, but with a short bit of code authoring required.
^(?=(\D*\d)|)(?=([^a-z]*[a-z])|)(?=([^A-Z]*[A-Z])|)(?=([a-zA-Z0-9]*[^a-zA-Z0-9])|).{4,8}$
Here you have five capturing groups - Check whether at least 3 of them are not null. A null group for capture effectively indicates that the alternative within the lookahead has been matched, and the capturing group on the left hand side could not be matched.
For example, in PHP:
preg_match("/^(?=(\\D*\\d)|)(?=([^a-z]*[a-z])|)(?=([^A-Z]*[A-Z])|)(?=([a-zA-Z0-9]*[^a-zA-Z0-9])|).{4,8}$/", $str, $matches);
$count = -1; // Because the zero-eth element is never null.
foreach ($matches as $element) {
if ( !empty($element)) {
$count += 1;
}
}
if ($count >= 3) {
// ...
}
Or Java:
Matcher matcher = Pattern.compile(...).matcher(string);
int count = 0;
if (matcher.matches())
for (int i = 1; i < 5; i++)
if (null != matcher.group(i))
count++;
if (count >= 3)
// ...
来源:https://stackoverflow.com/questions/26991679/the-best-way-to-match-at-least-three-out-of-four-regex-requirements