正则表达式:“密码必须至少有以下 4 个中的 3 个”

Posted

技术标签:

【中文标题】正则表达式:“密码必须至少有以下 4 个中的 3 个”【英文标题】:Regex: "password must have at least 3 of the 4 of the following" 【发布时间】:2015-09-20 09:02:53 【问题描述】:

我是 Regex 新手,到目前为止,我只将它用于简单的事情,例如“必须是数字或字母”。现在我必须做一些更复杂的事情。

我需要用它来验证一个密码,它必须是8-16个字符,无控制/非打印/非ASCII字符,并且必须至少具有以下三个:

一个大写字母 一个小写字母 一个数字0-9 一个符号字符($、%、& 等)

我在想我要做的就是写“一个大写字母,小写字母和数字,或者一个大写字母,小写字母和一个符号,或者一个大写字母,一个数字或一个符号,或者。 ...”以涵盖所有可能的“4 种中的 3 种”组合,但这似乎太过分了。有没有更简单的解决方案?

【问题讨论】:

您是否有充分的理由不能仅仅简化您的要求并要求所有四个条件? 是的。不要使用正则表达式。正则表达式是一个强大的工具,就像锤子一样强大。但是,如果您尝试用锤子拧螺丝,那将需要一段时间... 我的直觉说这可能是用于课堂作业 - 因为在实践中,限制密码的长度使其更容易破解。也就是说,您会发现只使用indexOf()(或您的语言等效项)来确定其中是否包含所需的字符之一。 好点,你是对的,没有什么特别的原因我不能要求所有四个条件。莱姆斯,谢谢你的提示。我想密码不需要最大长度。 @brandonscript,我来这里是因为一个服务器工具(Atlassian Crowd)使用这样的正则表达式格式来控制密码格式,没有其他选择。所以不一定是课堂作业。在我的公司,4 个条件中的 3 个是要求。 【参考方案1】:

执行此操作的正确方法是分别检查所有五个条件。但是,我认为你想要一个正则表达式是有原因的,你去吧:

/^((?=.*[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,但实际上没有匹配它们,你可以通过附加三个前瞻(?=.*X)(?=.*Y)(?=.*Z)来使用前面的方法 我们使用上面的来匹配所提到的四件事中的三件事。我们通过|(or) - cCD|cDS|CDS|CcSc = 小写字母,C = 大写字母,D = 数字,S = 特殊)遍历所有可能的组合

See it in action

【讨论】:

感谢您也提供细分!我想了解正则表达式,而不是让别人帮我做。 很好的解释!刚刚注意到命令是“cCD | CcS | CDS | cDS”而不是“cCD|cDS|CDS|CcS”,尽管我明白了。谢谢!【参考方案2】:

最好的方法是分别检查每个条件。如果您尝试将所有条件标准放入一个表达式中,性能将会受到影响(请参阅接受的答案)。我还强烈建议不要将密码长度限制为 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());
);

【讨论】:

如果你想证明性能,你应该通过遍历字符串中的字符来一次性完成。相反,这里我们有四个具有线性复杂度的操作,这与正则表达式解决方案所需的操作数量相同。但是,如果您不限于使用正则表达式,这确实是正确的方法,因为它比两种选择都更具可读性。 同意 - 我知道它可以简化并提高性能,但我想展示该方法与紧凑型解决方案背后的逻辑。【参考方案3】:

不确定它是否是 ios 问题,数字 [0-9] 为“d”的正则表达式没有按预期工作,例如有问题的字符串 =“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$

【讨论】:

以上是关于正则表达式:“密码必须至少有以下 4 个中的 3 个”的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式与扩展正则表达式区别

PHP 正则表达式总结

正则表达式

正则表达式

正则表达式“或“的使用

正则表达式 验证数字格式 非负数 小数点后保留两位 数字正则 double正则