【问题标题】:Is there a way to merge these two regex?有没有办法合并这两个正则表达式?
【发布时间】:2016-08-29 21:24:06
【问题描述】:

我需要使用以下规则检查密码字符串:

  • 只允许使用小写字母、大写字母、数字和一些特殊字符(见下文)。

  • 最少 8 个字符,最多 16 个字符。

  • 密码必须包含以下四个组中的三个组中的至少一个字符:

    • 小写字母
    • 大写字母
    • 数字字符
    • 特殊字符 (!@#$%&/=?_.,:;-)

为了实现这个目标,我做了两个验证。简单的是第一步,检查允许的字符和长度:

^[a-zA-Z0-9!@\#$%&/=?_.,:;\-]{8,16}$

第二个有点复杂,但感谢Stackoverflow answer

^((?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])|(?=.*[a-z])(?=.*[A-Z])(?=.*[!@\#$%&/=?_.,:;\-])|(?=.*[a-z])(?=.*[0-9])(?=.*[!@\#$%&/=?_.,:;\-])|(?=.*[A-Z])(?=.*[0-9])(?=.*[!@\#$%&/=?_.,:;\-])).{8,16}$

我认为两步解决方案可能既清晰又简单......但是...... 有没有办法合并两个正则表达式?

我想在 Java、JavaScript 和 Lua 上应用该解决方案。

【问题讨论】:

    标签: javascript java regex passwords


    【解决方案1】:

    首先让我强调我不喜欢你的密码政策。为什么要禁止其他符号或超过 16 个字符的密码?尽可能不要包含这些规则。

    为了清楚起见,我以扩展形式(即忽略空白)编写了这个正则表达式:

    /\A 
      (?=.{8,16}\z)                     # Must contain 8-16 characters
      (?!.*[^a-zA-Z\d!@#$%&\/=?_.,:;-]) # Must not contain other characters
      (?=.*\d)                          # Must contain a digit
      (?=.*[a-z])                       # Must contain a lower case character
      (?=.*[A-Z])                       # Must contain an upper case character
      (?=.*[!@#$%&\/=?_.,:;-])          # Must contain a symbol from this list
    /x
    

    上述模式解决了强制执行所有四个规则的问题。理论上,您可以将最后 4 个条件包装成四个“或”组 - 就像您原来的示例所做的那样。

    但是,我再次不推荐它。如果您将其作为函数内部的一系列单独检查来执行,您的代码将更加清晰、有用和可维护。 (例如,这意味着您可以显示更多有用的错误消息,而不仅仅是“正则表达式失败!”。

    但是既然你问了......这是正则表达式怪物:

    /\A 
      (?=.{8,16}\z)
      (?!.*[^a-zA-Z\d!@#$%&\/=?_.,:;-])
      (
        (?=.*\d)
        (?=.*[a-z])
        (?=.*[A-Z])
      |
        (?=.*\d)
        (?=.*[a-z])
        (?=.*[!@#$%&\/=?_.,:;-])
      |
        (?=.*\d)
        (?=.*[A-Z])
        (?=.*[!@#$%&\/=?_.,:;-])
      |
        (?=.*[a-z])
        (?=.*[A-Z])
        (?=.*[!@#$%&\/=?_.,:;-])
      )
    /x
    

    如果您不想/无法访问/x 修饰符,请删除所有空格。

    【讨论】:

    • 密码策略是我客户的要求,他已经在其他系统中实现了这个策略,所以目前很难更改。感谢@TomLord 的解决方案和建议!
    【解决方案2】:

    对整个验证使用单个正则表达式的缺点是,正则表达式很难阅读和维护。将正则表达式条件分成对每个条件的单个检查和对字符串长度的简单检查将是一个更合适且更具可读性的解决方案。在我看来,以下代码对密码的验证与单个正则表达式一样好,但更好地维护和阅读。

    public static void main(String[] args) {
        System.out.println(isPasswordValid("Ab$123456"));
        System.out.println(isPasswordValid("b$11234566"));
        System.out.println(isPasswordValid("Ab$1234634634534252"));
        System.out.println(isPasswordValid("$112512312512"));
        System.out.println(isPasswordValid("A$115 223"));
    }   
    
    private static boolean isPasswordValid(String password) {
        // The password is to short or to long
        if(password.length() < 8 || password.length() > 16) {
            return false;
        }
        int matchedConditions = 0;
        // Check for invalid characters
        if(password.matches(".*[^A-Za-z0-9!@#$%&/=?_.,:;-].*")) {
            return false;
        }
        // is an uppercase letter present, increase matched condition
        if(password.matches(".*[A-Z].*")){
            ++matchedConditions;
        }
        // is a lowercase letter present, increase matched condition
        if(password.matches(".*[a-z].*")){
            ++matchedConditions;
        }
        // is a numeric value present, increase matched condition
        if(password.matches(".*[0-9].*")){
            ++matchedConditions;
        }
        // is a special character present, increase matched condition
        if(password.matches(".*[!@#$%&/=?_.,:;-].*")){
            ++matchedConditions;
        }
        // Return if at least 3 conditions were met
        return matchedConditions >= 3;
    }
    

    输出:

    true
    true
    false
    false
    false
    

    【讨论】:

    • 谢谢,但是您的解决方案将针对此密码 Ab$12 34 返回 true,并且不允许使用空格,不是吗?
    • @DavidIsla 检查我的编辑,如果您包含无效字符列表,它仍然会更好阅读,您可以在其中包含您认为无效的所有内容。
    • 当然,您的解决方案是有效的,没错,但我想知道是否有办法将两者合并。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2017-12-11
    • 2021-08-28
    • 2013-02-26
    • 2021-12-30
    • 2011-04-15
    • 1970-01-01
    • 2019-09-08
    相关资源
    最近更新 更多