Erica Lan
Erica Lan

Reputation: 57

Trying to check a string that satisfies these conditions

Trying to use following code to check a string:

def check_password(x):
  if has_unique_letters(x) == False:
    print "Warning! Please ensure letters are not repeated."
  if has_even_vowels(x) == False:
    print "Warning! Please ensure password contains an even number of vowels."
  if has_special_character(x) == False:
    print "Warning! Please ensure password contains at least one of {@, #, *, $}"
  if has_divisible_numbers(x) == False:
    print "Warning! Please ensure all numbers are divisible by 2 or 3."
  print "Sorry, your password does not meet our criteria."
print "Congratulations, your password meets our criteria."

x = raw_input("Please set your password:")
check_password(x)


However I am confused about how to make:

print "Sorry, your password does not meet our criteria."

and:

print "Congratulations, your password meets our criteria." 

these two sentences show correctly.

I intend to show every "Warning!..." along with "Sorry,..." when one of these conditions is not meet, while show "Congratulation,..." when all of conditions are meet.
But with what I have, "Sorry,..." line will always shows and "Congratulations,..." line is not showing.

I know I must done wrong but how can I fix this?
Thanks!

Upvotes: 1

Views: 108

Answers (4)

PeterH
PeterH

Reputation: 868

EDIT: I like the last code example the most, and I think it is probably the best practice for something like this.

A simple way to solve the problem would be to do something like this:

def check_password(x):
    bad_password = False
    if has_unique_letters(x) == False:
        print "Warning! Please ensure letters are not repeated."
        bad_password = True
    if has_even_vowels(x) == False:
        print "Warning! Please ensure password contains an even number of vowels."
        bad_password = True
    if has_special_character(x) == False:
        print "Warning! Please ensure password contains at least one of {@, #, *, $}"
        bad_password = True
    if has_divisible_numbers(x) == False:
        print "Warning! Please ensure all numbers are divisible by 2 or 3."
        bad_password = True

    if bad_password == True:
        print "Sorry, your password does not meet our criteria."
    else:
        print "Congratulations, your password meets our criteria."


x = raw_input("Please set your password:")
check_password(x)

Simply adding a bool to set if the password is bad saves you from needing to do any weird nested logic and doesn't overly complicate the code.

However, there are some more elegant ways to solve that problem. Let me know if you would like to see some of them. But as far as functionality the above code should work for your needs.

Here is a slightly more functional way to handle the errors based on Alexander's answer.

def check_password(password):
    # by adding an array of error messages it enables you to pass all of the errors to other functions that can handle
    #   everything an independent way.
    errors = []
    if not has_unique_letters(password):
        errors.append("Warning! Please ensure letters are not repeated.")
    if not has_even_vowels(password):
        errors.append("Warning! Please ensure password contains an even number of vowels.")
    if not has_special_character(password):
        errors.append("Warning! Please ensure password contains at least one of {@, #, *, $}")
    if not has_divisible_numbers(password):
        errors.append("Warning! Please ensure all numbers are divisible by 2 or 3.")
    return errors


def handle_password_errors(errors):
    # A function that can handle all of the password errors. This can print the errors or set flags in a GUI or any
    # number of other things with out having to change any of the other functions.
    if errors:
        print "Sorry, your password does not meet our criteria."
        for e in errors:
            print(e)
    else:
        print "Congratulations, your password meets our criteria."


password = raw_input("Please set your password:")
check_password(password)

This is my prefered method. Now the question is how do you pass the PASSWORD_ERRORS list to the functions that need it? If these methods are all in a class I like making the const a part of the init or just declared at the top of the class (inside of the class).

# Using a dictionary like this to store all of the possible password errors makes it easier if you want to change a
#   specific error message in the future. It also enables you to add more associations to your errors. For example you
#   can add a error flag to pass to a UI or function call.
PASSWORD_ERRORS = {
    'unique_letter_error': {
        'text': "Warning! Please ensure letters are not repeated.",
    },
    'even_vowels_error': {
        'text': "Warning! Please ensure password contains an even number of vowels.",
    },
    'special_character_error': {
        'text': "Warning! Please ensure password contains at least one of {@, #, *, $}",
    },
    'divisible_numbers_error': {
        'text': "Warning! Please ensure all numbers are divisible by 2 or 3."
    }
}


def check_password(password):
    # by adding an array of error messages it enables you to pass all of the errors to other functions that can handle
    #   everything an independent way.
    errors = []
    if not has_unique_letters(password):
        errors.append(PASSWORD_ERRORS['unique_letter_error'])
    if not has_even_vowels(password):
        errors.append(PASSWORD_ERRORS['even_vowels_error'])
    if not has_special_character(password):
        errors.append(PASSWORD_ERRORS['special_character_error'])
    if not has_divisible_numbers(password):
        errors.append(PASSWORD_ERRORS['divisible_numbers_error'])
    return errors


def handle_password_errors(errors):
    # A function that can handle all of the password errors. This can print the errors or set flags in a GUI or any
    # number of other things with out having to change any of the other functions.
    if errors:
        print "Sorry, your password does not meet our criteria."
        for e in errors:
            # Here you can print the text or if the PASSWORD_ERRORS has more attributes you can handle the
            #   errors in different ways.
            print(e['text'])
    else:
        print "Congratulations, your password meets our criteria."


password = raw_input("Please set your password:")
check_password(password)

Upvotes: 4

Ali Öztürk
Ali Öztürk

Reputation: 29

Maybe you can try like this; IN this code you'll see warning message till you fix your password, but for ex, if there are 2 errors, then first error message will be something from top(from if-elif blog) , then whenever you fix your top error, you'll receive second error message which below first error and you'll also fix it, while fixing them 1 by 1 you'll receive congrats msg at last.

def check_password(x):
problem = 0
if has_unique_letters(x)==False:
    problem = 1
elif has_even_vowels(x)==False:
    problem = 2
elif has_special_character(x)==False:
    problem = 3
elif has_divisible_numbers(x)==False:
    problem = 4

if(problem == 1):
    print "Warning! Please ensure letters are not repeated."
elif(problem ==2):
    print "Warning! Please ensure password contains an even number of vowels."
elif(problem==3):
    print "Warning! Please ensure password contains at least one of {@, #, *, $}"
elif(problem==4):
    print "Warning! Please ensure all numbers are divisible by 2 or 3."
elif(problem==0):
    print "Congratulations, your password meets our criteria."

Upvotes: 1

Adam Smith
Adam Smith

Reputation: 54183

I actually prefer over-engineering this a bit. Try the following:

class BadPasswordError(ValueError):
    pass

def check_password(p:str, *validators:'(lambda p: True, "Error message")') -> bool:
    for validator, err in validators:
        if not validator(p):
            raise BadPasswordError(err)
    return True

This lets you write any number of custom validators and pass them all at once.

password_validators = [(has_unique_letters, "Warning! Please ensure letters are not repeated."),
                       (has_even_vowels, "Warning! Please ensure password contains an even number of vowels."),
                       (has_special_characters, "Warning! Please ensure password contains at last one of {@, #, *, $}."),
                       (has_divisible_numbers, "Warning! Please ensure all numbers are divisible by 2 or 3.")]

try:
    ok = check_password(user_inputted_password, password_validators)
except BadPasswordError as e:
    print(e)

You could even create a custom decorator to create your password validators in-place.

import functools

def password_validator(errmsg):
    def wrapper(f):
        @functools.wraps(f)
        def wrapped(*args):
            if f(*args):
                return True
            else:
                raise BadPasswordError(errmsg)
        return wrapped
    return wrapper

@password_validator("Warning! Please ensure letters are not repeated.")
def has_unique_letters(p):
    return len(set(p)) == len(p)

# repeat for each validator....

Then all you'll have to do is run each validator in turn and catch BadPasswordErrors.

validators = [has_unique_letters, has_even_vowels, has_special_characters, has_divisible_numbers]
for validator in validators:
    try:
        validator(p)
    except BadPasswordError as e:
        print(e)

Upvotes: 1

Alexander
Alexander

Reputation: 109546

Create a list that contains all errors in the password. If there are errors, state that the password does not meet the criteria and then print all of the password error types. Otherwise, print that it meets the criteria.

def check_password(password):
    errors = []
    if not has_unique_letters(password):
        errors.append("Warning! Please ensure letters are not repeated.")
    if not has_even_vowels(password):
        errors.append("Warning! Please ensure password contains an even number of vowels.")
    if not has_special_character(password):
        errors.append("Warning! Please ensure password contains at least one of {@, #, *, $}")
    if not has_divisible_numbers(password):
        errors.append("Warning! Please ensure all numbers are divisible by 2 or 3.")
    if errors:
        print "Sorry, your password does not meet our criteria."
        for e in errors:
            print(e)
    else:
        print "Congratulations, your password meets our criteria."

password = raw_input("Please set your password:")
check_password(password)

Upvotes: 5

Related Questions