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

前端 未结 3 1243

I\'m a Regex newbie, and so far have only used it for simple things, like \"must be a number or letter\". Now I have to do something a bit more complex.

I need to u

相关标签:
3条回答
  • 2021-01-05 22:36

    The best way to do this is by checking each condition separately. Performance will suffer if you try to fit all conditional criteria into one expression (see the accepted answer). I also highly recommend against limiting the length of the password to 16 chars — this is extremely insecure for modern standards. Try something more like 64 chars, or even better, 128 — assuming your hashing architecture can handle the load.

    You also didn't specify a language, but this is one way to do it in 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());
    });
    
    0 讨论(0)
  • 2021-01-05 22:55

    Not sure if its a iOS thing, the regex with "d" for digits [0-9] wasn't working as expected, example String that had issues = "AAAAAA1$"

    The fix below works fine in Objective-C and 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}$
    
    0 讨论(0)
  • 2021-01-05 22:57

    The correct way to do this is to check all of the five conditions separately. However, I assume there is a reason you want a regex, here you go:

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

    Explanation:

    • We want to match the whole thing, hence we surround it with ^$
    • .{n,m} matches between n and m characters (8 and 16 in our case).
    • The general way you can check if a string contains something, without actually matching it is by using positive lookahead (?=.*X), where X is the thing you want to check. For example, if you want to make sure the string contains a lowercase letter you can do (?=.*[a-z]).
    • If you want to check if a string contains X, Y and Z, but without actually matching them, you can use the previous recipe by appending the three lookaheads (?=.*X)(?=.*Y)(?=.*Z)
    • We use the above to match three of the four things mentioned. We go through all possible combinations with |(or) - cCD|cDS|CDS|CcS (c = lowercase letter, C = capital letter, D = digit, S = special)

    See it in action

    0 讨论(0)
提交回复
热议问题