正则表达式:"password must have at least 3 of the 4 of the following"

Regex: "password must have at least 3 of the 4 of the following"

我是 Regex 新手,到目前为止只将它用于简单的事情,例如 "must be a number or letter"。现在我必须做一些更复杂的事情。

我需要用它来验证密码,密码必须是 8-16 个字符,不能包含 control/non-printing/non-ASCII 个字符,并且必须至少包含以下三个:

我在想我必须做的是写一些类似 "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...." 的东西来涵盖所有可能的“4 选 3”组合,但这似乎太多了。有更简单的解决方案吗?

最好的方法是分别检查每个条件。如果您尝试将所有条件标准都放入一个表达式中,性能将会受到影响(请参阅已接受的答案)。我还强烈建议不要将密码长度限制为 16 个字符——这对于现代标准来说是极其不安全的。尝试更多类似 64 个字符,或者更好的 128 个字符 — 假设您的哈希架构可以处理负载。

您也没有指定语言,但这是 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());
});

正确的做法是分别检查所有五个条件。但是,我认为您需要正则表达式是有原因的,给您:

/^((?=.*[A-Z])(?=.*[a-z])(?=.*\d)|(?=.*[a-z])(?=.*\d)(?=.*[$\%\&])|(?=.*[A-Z])(?=.*\d)(?=.*[$\%\&])|(?=.*[A-Z])(?=.*[a-z])(?=.*[$\%\&])).{8,16}$/

解释:

  • 我们想要匹配整个东西,因此我们用 ^$
  • 包围它
  • .{n,m} 匹配 nm 字符(在我们的例子中是 8 和 16)。
  • 检查一个字符串是否包含某些东西而不实际匹配它的一般方法是使用正向前瞻 (?=.*X),其中 X 是您要检查的东西。例如,如果要确保字符串包含小写字母,可以执行 (?=.*[a-z]).
  • 如果你想检查一个字符串是否包含 XYZ,但实际上没有匹配它们,你可以通过附加三个 lookaheads (?=.*X)(?=.*Y)(?=.*Z)
  • 我们用上面的来匹配提到的四件事中的三件事。我们通过 |(or) - cCD|cDS|CDS|CcSc = 小写字母,C = 大写字母,D = 数字,S = 特殊)

See it in action

不确定它是否是 iOS 的东西,带有 "d" 数字 [0-9] 的正则表达式没有按预期工作,例如有问题的字符串 = "AAAAAA1$"

下面的修复在 Objective-C 和 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}$