ProXicT ProXicT - 2 months ago 7
C++ Question

Regex specific password restrictions

I need to validate password to fulfill at least three combinations of these rules:

Upper case, lower case, number, special char


The password also needs to be at least 8 characters long.

EDIT

I know these password restrictions are contraproductive, it's a request, not my naive idea of getting stronger passwords.

Example of valid passwords:

Password3 // Upper case, lower case, number
Password! // Upper case, lower case, special
password3! // Lower case, number, special
PASSWORD3! // Upper case, number, special
Password3! // Upper case, lower case, number, special


Example of invalid passwords:

password // Only lower case
password3 // Only lower case and number
password! // Only lower case and special
Password // Only Upper case and lower case
Pw3! // Too short


Here is a regex I wrote:

(?=.*[A-z\d]+)(?=.*[A-z@!?]+)(?=.*[a-z\d@!?]+)(?=.*[A-Z\d@!?]+)[A-z\d@!?]{8,}


Hopefuly, I know why this regex matches invalid passwords too, if so, how can I say then, that the expression must contain everything from the group and not just one match?

Answer

It's obvious that your problem is a kinda hard one. So I would split it into more understandable pieces. That will help so much. Look at this example I made:

#include <iostream>
#include <string>
#include <regex>

int main(){

    bool upper_case = false; //saves the result if upper-case characters were found.
    bool lower_case = false; //same for lower-case
    bool number_case = false; //...
    bool special_char = false;


    std::regex upper_case_expression{ "[A-Z]+" }; //here is the very simple expression for upper_case search
    std::regex lower_case_expression{ "[a-z]+" }; //for lower-case
    std::regex number_expression{ "[0-9]+" }; //...
    std::regex special_char_expression{ "[@!?]+"};


    std::string pw;


    bool done = false; //let's assume we're not done

    do{ //do ask-for-password as long were not done

        std::cout << "Type in a valid password: ";
        std::getline(std::cin, pw); //get input

        if (pw.length() <= 8){ //too short!
            std::cout << "Invalid password! Try again . . .\n\n";
        }
        else{

            upper_case = std::regex_search(pw, upper_case_expression); //save the result, if the expression was found.
            lower_case = std::regex_search(pw, lower_case_expression); //....
            number_case = std::regex_search(pw, number_expression);
            special_char = std::regex_search(pw, special_char_expression);

            //like: sum_of_positive_results = 1 + 0 + 1 + 1 (true/false as an integer)
            int sum_of_positive_results = upper_case + lower_case + number_case + special_char; 

            if (sum_of_positive_results < 3){ //not enough booleans were true!
                std::cout << "Invalid password! Try again . . .\n\n";
            }
            else{ //otherwise it's valid!
                std::cout << "That's a valid Password!" << std::endl;
                done = true;
            }
        }

    } while (!done);

    return 0;
}

output:

Type in a valid password: password
Invalid password! Try again . . .

Type in a valid password: Password
Invalid password! Try again . . .

Type in a valid password: password!
Invalid password! Try again . . .

Type in a valid password: password3
Invalid password! Try again . . .

Type in a valid password: not valid!
Invalid password! Try again . . .

Type in a valid password: Password!
That's a valid Password!

As you can see, that's way nicer and easier to follow. I hope that helped you!