So here is the issue. I have a series of functions with which an inputString from the user gets checked to meet all of the set password criteria:
Passwords must be at least 5 characters long
Passwords must contain at least one upper case letter
Passwords must contain at least two numbers
Passwords may not contain the characters "E" or "e"
Passwords must include at least one non-alphanumeric character.
A password may not be a frequently used password: 'password', '12345',
'qwerty', 'letmein', 'trustno1', '000000', 'passw0rd,'Password'
My last function attempts to collect all of the functions defined into a single usable module function. There are no errors running the program but there is a bug which always prints, "Invalid! Password must contain special character." Why is that so? And what other bugs or fixed do you guys suggest to make this code more efficient or readable?
def isFiveCharacters(inputString):
while len(inputString) > 5:
return True #print('Contains at least 5 characters, ')
else:
print('Invalid! Password must cantain more than 5 characters')
return False
def hasUpperCase(inputString):
x = any(char.isupper() for char in inputString)
if x == True:
return True #print ('an uppercase letter, ')
if x == False:
print('Invalid! Password must contain an upper case letter')
return False
def hasNumbers(inputString):
count = 0
for char in inputString:
if char == char.isdigit():
count += 1
if count >= 2:
#print ('two numbers, ')
return True
elif count < 2:
print ('Invalid! Password must contain two numbers')
return False
def hasLetterE(inputString):
for char in inputString:
if 'E' and 'e' in inputString:
print('Invalid! Password cannot contain the letter "E"')
return False
else:
#print('does not contain the letter E, ')
return True
#if 'e' in inputString:
# print('Password cannot contain the letter "e"')
# return None
def nonAlphaNumChar(inputString):
special_char = ['!','#','$','%','#','^','&','*']
if inputString == special_char * 2:
#print('a special character, ')
return True
else:
print('Invalid! Password must contain a special character')
return None
def usedPasswords(inputString):
used_passwords = ('password','12345','qwerty','letmein','trustno1','000000','passw0rd','Password')
if used_passwords == inputString:
print('Invalid! Password must be original.')
return False
def passwordCriteria(inputString):
isFiveCharacters(inputString)
hasUpperCase(inputString)
hasNumbers(inputString)
hasLetterE(inputString)
nonAlphaNumChar(inputString)
usedPasswords(inputString)
while inputString == True:
print('Valid Password')
return True
if inputString == False:
print('Error, invalid password')
return False
return None
I am just going to point out the obvious mistake:
You should collect the values returned by the functions like this
valid = isFiveCharacters(inputString)
# then just use the boolean values with an `and`
valid = valid and hasUpperCase(inputString)
valid = valid and hasNumbers(inputString)
# and so on
# then use
if valid:
print("Valid Password")
else:
print("Invalid Password")
I suggest reading about functions the return statement and the while loop in detail and getting a clear understanding of how they work.
Related
for c in password:
if not any(c in password for c in symbols):
return False
if not any(c.isdigit() for c in password):
return False
if not any(c.islower() for c in password):
return False
if not any(c.isupper() for c in password):
return False
return
print(password)
f = open("demofile2.txt", "a")
f.write(password + "\n")
f.close()
You want to avoid doing extra work when verifying that your password satisfies all requirements. In my example, I've looked at each character only once and am performing the required checks every time I look at a different character.
In the example you provided, you're actually verifying that every character meets your requirements for every character in the password O(N*N) - this is not recommended.
Lastly, make sure you understand what the password requirements are. It seems like your logic is incorrect when trying to verify that a character is both lowercase and uppercase simultaneously.
edit: The author clarified in comments that in order for a password to be valid, that password must have at least:
one symbol
one digit
one lowercase character
one uppercase character
has_symbol = False
has_digit = False
has_lower = False
has_upper = False
for c in password:
if has_symbol and has_digit and has_lower and has_upper:
break
elif c in symbols:
has_symbol = True
elif c.isdigit():
has_digit = True
elif c.islower():
has_lower = True
elif c.isupper():
has_upper = True
if has_symbol and has_digit and has_lower and has_upper:
print(password)
f = open("demofile2.txt", "a")
f.write(password + "\n")
f.close()
else:
return False
you should take care about time complexity by avoiding unnecessary
loops.
this will help you:
from string import punctuation
def check_pass(password):
return all([any(filter(str.islower, password)),
any(filter(str.isupper, password)),
any(filter(str.isdigit, password)),
any(filter(lambda x: x in punctuation, password))
]
)
def save_password(password):
if check_pass(password):
with open("demofile2.txt", "a") as f:
f.write(password)
print(password)
else:
print('Not Accepted!')
# Test
save_password('1#cA')
I am coding a password analyzer with several properties, one being that the user's password must not have special characters (##$%^&*) except for ! (exclamation mark) and _ (underscore). I am using the .isalnum() method for this purpose but I cannot figure out a way to make it so it doesn't return True when ! or _ is used WITH any other special character (ex: Python$ returns False but Python_ returns True).
Here is my code:
password = input('Enter a password: ')
if not password.isalnum():
if '_' in password or '!' in password:
pass
else:
print('Your password must not include any special characters or symbols!')
The most intuitive way is to check every character.
if not all(c.isalnum() or c in '_!' for c in password):
print('Your password must not include any special characters or symbols!')
This is one way. replace the ! and _ withe empty string and then check with isalnum().
password = input('Enter a password: ')
pwd = password.replace('_', '').replace('!', '')
if pwd.isalnum() and ('_' in password or '!' in password):
pass
else:
print('Your password must not include any special characters or symbols!')
Another way of checking it is by using regex
import re
x = input('Enter a password: ')
t = re.fullmatch('[A-Za-z0-9_!]+', x)
if not t:
print('Your password must not include any special characters or symbols!')
def is_pass_ok(password):
if password.replace('_', '').replace('!','').isalnum():
return True
return False
password = input('Enter a password: ')
if not is_pass_ok(password):
print('Your password must not include any special characters or symbols!')
By removing all allowed special characters, i.e. _ and !:
password.replace('_', '').replace('!','')
it remains only to check for alphanumeric characters (.isalnum()).
I'm trying to make a program where I input a name and a surname and the code checks if the name is invalid (list of invalidiations below). If it has any invalidations, it asks me to say the name again and presents me a list of all the invalidations.
Invalidations list (I'll show the code version too):
- The name has digits
- The name has symbols
- The name has no spaces
- It has more then one space
- One of the names is either too short or too long
- The first letter of the name is a space
- The last letter of the name is a space
I can't use exceptions here, because these are not code erros. I've made it with Ifs, but it got to a point where there a simply lots of Ifs for it to be viable.
def has_digits(name):
digits = any(c.isdigit() for c in name)
if digits == True:
return True
print("Your name has digits.")
else:
return False
def has_symbols(name):
symbols = any(not c.isalnum() and not c.isspace() for c in name)
if symbols == True:
return True
print("Your name has symbols.")
else:
return False
def has_no_spaces(name):
spaces = any(c.isspace() for c in name)
if not spaces == True:
return True
print("You only gave me a name.")
else:
return False
def many_spaces(name):
m_s = name.count(' ') > 1
if m_s == True:
return True
print("Your name has more than one space.")
else:
return False
def unrealistic_length(name, surname):
length= (float(len(name)) < 3 or float(len(name)) > 12) or float(len(surname)) < 5 or float(len(surname) > 15)
if length == True:
return True
print("Your name has an unrealistic size.")
else:
return False
def first_space(name):
f_s = name[0] == " "
if f_s == True:
return True
print("The first letter of your name is a space.")
else:
return False
def last_space(name):
l_s = name[-1] == " "
if l_s == True:
return True
print("The last letter of your name is a space.")
else:
return False
name = "bruh browski"
namesplit = name.split(" ")
name1 = namesplit[0]
name2 = namesplit[1]
print(has_digits(name))
print(has_symbols(name))
print(has_no_spaces(name))
print(many_spaces(name))
print(unrealistic_length(name1, name2))
print(first_space(name))
print(last_space(name))
Maybe the prints shouldn't be in the defs themselves. I don't know. I'm almost sure doing a for loop is the way to go, but I just can't imagine how to do it.
Result:
False
False
False
False
False
False
False
The methods you've used to define exactly what counts as each "invalidation" will have to stay, unless you can replace them with something else that does the same thing. But you can check all of those conditions at once using a generator expression:
if any(is_invalid(name) for is_invalid in [
has_digits, has_symbols, has_no_spaces, many_spaces, unrealistic_length, first_name, last_name
]):
# then this string is invalid
# otherwise, all of those returned false, meaning the string is valid.
You can then use that condition to determine when to stop asking the user, or however else you need to.
If you wanted to not individually define all those functions, you could also maybe use lambdas to do the same thing.
As a sidenote, before actually using this in production for checking the validity of names, I advise having a look at the list of Falsehoods Programmers Believe about Names. It's a fun read even if it's not relevant to your use case, though.
You could have a single function which calls all of your other functions and handles it appropriately.
def master_verify(name):
# Put all your verify functions in the list below.
verify_funcs = [has_digits, has_symbols, has_no_spaces, many_spaces,
unrealistic_length, first_space, last_space]
# It will return True if any your functions return True. In this case,
# returning True means the name is invalid (matching your other
# function design). Returning False means the name is valid.
return any(is_invalid(name) for is_invalid in verify_funcs)
Since you mentioned you want the program to find any name errors and ask the user to try again, we can write a loop to handle this.
def get_name():
while True:
# Loop until you get a good name
name = input("Enter your name: ").strip()
if master_verify(name):
# Remember, if True this means invalid
print("Invalid name. Try again.")
continue # continue jumps to the top of a loop, skipping everything else.
return name # Will only get here if the name is valid.
I also suggest you should do the name and surname split inside your unrealistic_length function.
Then, all you need to do is
name = get_name()
# All of the validation has already happened.
print(f"The correct and validated name is: {name}")
Last but not least, anything in a function after a return is unreachable. So a lot of your prints will never happen. Put the print statements before your return.
Alright. I've managed to do it by myself. I still fill there's a better way to do it, but this is the way I found.
errors_list = []
print("Hi. Tell me your first and last name.")
def choose_name(name):
global fname
global sname
fname = ""
sname = ""
global errors_list
try:
no_letters = any(c.isalpha() for c in name)
no_spaces = name.count(" ") == 0
digits = any(c.isdigit() for c in name)
symbols = any(not c.isalnum() and not c.isspace() for c in name)
many_spaces = name.count(" ") > 1
first_space = name[0] == " "
last_space = name[-1] == " "
if no_letters == False:
errors_list.append("It has no letters")
if no_spaces == True:
errors_list.append("It has no spaces")
else:
namesplit = name.split(" ")
fname = namesplit[0]
sname = namesplit[1]
pass
if fname and sname is not "":
bad_length = (float(len(fname)) < 3 or float(len(fname)) > 12) or float(len(sname)) < 4 or float(len(sname) > 15)
if bad_length == True:
errors_list.append("One of your names has an unrealistic size")
pass
else:
bad_length = (float(len(name)) < 3 or float(len(name)) > 12)
if bad_length == True:
errors_list.append("It has an unrealistic size")
pass
if digits == True:
errors_list.append("It has digits")
pass
if symbols == True:
errors_list.append("It has symbols")
pass
if many_spaces == True:
errors_list.append("It has more than one space")
pass
if first_space == True:
errors_list.append("The first letter is a space")
pass
if last_space == True:
errors_list.append("The last letter is a space")
pass
except IndexError:
print("You must write something. Try again.")
name = input("My name is ").title()
choose_name(name)
name = input("My name is ").title()
choose_name(name)
while True:
if len(errors_list) != 0:
print("Your name has these errors:")
for i in errors_list:
print(" " + str(errors_list.index(i) + 1) + "- " + i + ".")
print("Try again.")
errors_list.clear()
name = input("My name is ").title()
choose_name(name)
else:
print("Nice to meet you, " + fname + " " + sname + ".")
break
Result when I type the name '----... '
Hi. Tell me your first and last name.
My name is ----...
Your name has these errors:
1- It has no letters.
2- It has symbols.
3- It has more than one space.
4- The last letter is a space.
Try again.
My name is
I am supposed to write a script with the following criteria:
Write a function called validatePassword that takes a password string as a parameter and returns true or false. The function should only return true if:
The password is at least 8 characters
The password contains at least one number
The password contains at least one upper case letter. Hint: use the isupper() string function.
The password contains a symbol one of the symbols !##$%^&*()+=
I have this so far:
def validatePassword(pswd):
if len(pswd)> 8:
return True
else:
return False
for char in pswd:
if char in '01234567890':
return True
else:
return False
for char in pswd:
if char in '!##$%^&*()_+=':
return True
else:
return False
for char in pswd:
if char.isupper and char .islower:
return True
else:
return False
return True
while False:
print("There was an error with your password")
print (validatePassword(Herseuclds))
I know that print (validatePassword(Herseuclds)) has a syntax error because I am missing the variable but I just don't get how to do this.
def validatePassword(pswd):
if len(pswd) < 8:
return False
number_in_password = False
for char in pswd:
if char in '012356789':
number_in_password = True
if not number_in_password:
return False
symbol_in_password = False
for char in pswd:
if char in '!##$%^&*()_+=':
symbol_in_password = True
if not symbol_in_password:
return False
uppercase_in_password = False
for char in pswd:
if char.isupper():
uppercase_in_password = True
if not uppercase_in_password:
return False
#this only happens if nothing above has disqualified the password
return True
print (validatePassword("herseuc"))
print (validatePassword("herseuclds"))
print (validatePassword("herseuclds!"))
print (validatePassword("herseuclds!123"))
print (validatePassword("herseuclds!123A"))
The main issue with your code is in the last line.
print (validatePassword(Herseuclds))
Right now, the interpreter thinks Herseuclds is a variable, and not a string. If Herseuclds is the password, and not a variable describing the password, then you need quotes around it to make it a string literal.
print (validatePassword("Herseuclds"))
You obviously haven't defined a variable called Herseuclds anywhere in your program, but the program thinks Herseuclds is a variable and not a string, so it throws the error.
Best of luck, and happy coding!
First issue is that you are passing an undeclared variable to your function. See silentphoenix's answer for details.
Secondly, your program only check to see if AT LEAST ONE condition is met, not all.
If a password is 8 characters long, it will return true even if the password doesn't satisfy the other requirements.
I am not going to write your code for you, but I can pseudocode the issue:
def validatePassword(pswd):
if len(pswd) < 8:
return False
# if there isn't a number:
return False
# if there isn't a symbol:
return False
# if there isn't an upper and lowercase:
return False
return True
while True:
print("There was an error with your password")
print (validatePassword("Herseuclds"))
sidenote: watch your indentation :)
Since you can use is.upper() you can also utilize is.digit() to check for numbers instead of having to write down actual digits.
Another thing to speed it up, since they all have to be done at the same time, you can check if the password validates those requirements in one line with any()
def validatePassword(pswd):
l = []
if len(pswd)> 8:
for char in pswd:
l.append(char)
if any(l for x in l if x.isdigit()) and any(l for x in l if x.isupper()) and any(l for x in l if x in '!##$%^&*()_+='):
print('Success')
else:
print('Try again')
while True:
a = input('What is your password?')
validatePassword(a)
At the beginning there's an minimum check to see if the lengeth is greater than 8. If it is, the word gets broken up into a list. This allows any() to be used and checked against the remainding requirements.
def valid_password(password):
return (
# The password is at least 8 characters
len(password) >= 8 and
# The password contains at least one number
any(c in "0123456789" for c in password) and
# The password contains at least one upper case letter
any(c.isupper() for c in password) and
# The password contains a symbol one of the symbols !##$%^&*()+=
any(c in "!##$%^&*()+=" for c in password))
Example:
from getpass import getpass
while not valid_password(getpass('Enter password: ')):
print('invalid password. Try again')
The task is to get a user to input a password then, using recursion, make sure it has no vowels in it. If it does then let the user re-enter the password. This is what i have so far:
def passwordCheck(pwd):
"""checks if pwd has any vowels in it."""#doc string
vowels = 'aeiou'#specifies the characters that aren't allowed
if pwd == '':
return 0
elif pwd == None:
return None#Shouldn't be necessary but just in case
elif pwd[0] not in vowels:#checks that the 1st(0th) character is not a vowel
return passwordCheck(pwd[1:])#gets rid of the 1st(0th) character and starts again
elif pwd[0] in vowels:#checks if the 1st(0th) character is a vowel
return 1#if it is, stops the function calls and returns a value
password = str(input('Please enter a password with no vowels in it: '))#asks user to input their new password
x = passwordCheck(password)#checks the password is valid, i.e. no vowels
while x == 1:#when the password entered contains a vowel
print('\nSorry, that is not a valid password.\nYour password cannot contain any vowels.')#tells the user why their password is invalid
password = str(input('\nPlease enter a different password: '))#gives the user a chance to re-enter their password
x = passwordCheck(password)#checks to make sure the new password is valid
print('\nCongratulations, you have entered a valid password!')#tells the user if their desired password is valid
print('\nYou are now able to log on to the system with these credentials.')#could've been included on the previous line but looks neater here
I know this is probably not the most pythonic way of doing it but it works for me in most cases. I'd love to hear a better way but ideally someone can help in the same style. I don't want to just copy someones code without understanding it.
The question i have is dealing with the case where the user enters no password at all. The first if statement:
if pwd == '':
return 0
I thought it just dealt with the case when the string had been fully recursed through, i.e. no vowels, but after a minutes inspection it's obvious this applies to no password as well.
I had also tried using:
if pwd == None:
return something
Now i'm thinking the problem could be because i said:
password = str(input('######'))
but i've fiddled with that as well and still can't can't seem to make that work either! I've tried google and searching stackoverflow but no luck so if anyone has any ideas/solution they think might be helpful I'd be very grateful to hear them. Thank you very much.
My main question is:
How can i differentiate between a string that's empty because it's been recursed through and the user inputting nothing?
Solved.
ended up using
def passwordValid(pwd):
if len(pwd)>0 and passwordCheck(pwd)==0:
return pwd
else: return 'Fail'
password = str(input('Please enter a password with no vowels in it: '))#asks user to input their new password
y = passwordValid(password)#checks the password is valid, i.e. no vowels
while y == 'Fail':#when the password entered contains a vowel
print('\nSorry, that is not a valid password.\nYour password cannot contain any vowels or be empty.')#tells the user why their password is invalid
password = str(input('\nPlease enter a different password: '))#gives the user a chance to re-enter their password
y = passwordValid(password)#checks to make sure the new password is valid
print('\nCongratulations, you have entered a valid password!')#tells the user if their desired password is valid
print('\nYou are now able to log on to the system with these credentials.')#could've been included on the previous line but looks neater here
Thank you Wayne Werner for fixing the title and the main question.
This problem can be broken down into (at least) three distinct subproblems:
check whether a string contains vowels
check whether a string is a valid password (length > X and has vowels)
get a password from the user
Your code should reflect this structure. You could therefore use the following function layout:
def has_vowels(string):
if not string: # check for empty string
return False # empty strings never have vowels
# TODO we have a non-empty string at this point and can use recursion
def is_valid_password(string):
return len(string) > 0 and not has_vowels(string)
def request_password():
while True: # use an endless loop here, we don't won't to repeat
# the "input" statement. We could also change this to
# something like `for i in range(3)` to allow only a limited
# number of tries.
passwd = input('Please enter a password with no vowels in it: ')
# TODO check if input is valid, if yes, return, if no, print an error
Don't attempt to solve both problems with a single method. You have two ditinct critera: no vowels; minimum length.
def isPasswordValid(pwd):
return len(pwd) > 4 and not passwordCheck(password)
x = isPasswordValid(password)
...
You could solve this with recursion by adding another parameter which indicates how many characters have been looped through, but that is clumsy and offers no real benefit.
You can't differentiate between an empty string and an empty string. You can however set the variable to None, or to a string like "__no_string_entered_yet". That said, I don't see why you would need to, see the other answers.
I believe this does what your question asks for:
Not allow an empty password (different than a "blank" password?)
Not allow vowels in the password
I opted not use if/elif/else in favor of structuring it so that valid characters "fall through"
def pwd_check(s):
vowels = 'aeiou'
if len(s) == 0: return False # This is only valid in the first iteration
if s[0] in vowels: return False
if len(s) == 1: return True # Success: a 1 character pwd with no vowels
return pwd_check(s[1:])
I thought about putting checks in to make sure that a string like ' ' was not passed in, but I didn't see that explicitly asked for. pwd_check(password.strip()) solves this problem.
Here's how I like to do.
For the fun, I added conditions of minimum and maximum lengths for the password:
def passwordCheck(pwd,vowels = 'aeiou',minimum=5,maximum=12):
if pwd == '':
return 0,None,None
elif pwd[0] in vowels:
return -1,None,None
else:
y = passwordCheck(pwd[1:])[0]
if y==-1:
return -1,None,None
else:
return y + 1,minimum,maximum
mess = 'Please enter a password with no vowels in it: '
while True:
x,miin,maax = passwordCheckstr(input(mess))
if x==-1:
mess = ('\nSorry, that is not a valid password.\n'
'Your password cannot contain any vowels.\n'
'Please enter a different password: ')
elif x==0:
mess = ('\nSorry, you must enter a password.\n'
'Please do enter a password: ')
elif x<miin:
mess = ('\nSorry, the password must have at least %d characters.\n'
'The string you entered has %d characters.\n'
'Please, enter a new longer password: ' % (miin,x))
elif x>maax:
mess = ('\nSorry, the password must have at most %d characters.\n'
'The string you entered has %d characters.\n'
'Please, enter a new shorter password: ' % (maax,x))
else:
print ('\nCongratulations, you have entered a valid password!\n'
'\nYou are now able to log on to the system with these '
'credentials.')
break
edit
Another kind of algorithm.
I wasn't satisfied to return such tuple as -1,None,None
def check_password(forbidden,minimum,maximum):
def passwordCheck(pwd,cnt=0,forbid = forbidden,
miin=minimum,maax = maximum):
# cnt is the number of preceding turns of recursion
# that have been already executed.
if pwd == '':
if cnt==0:
# cnt==0 means that it's the first turn of recursion
# since pwd is '', it means no entry has been done
return 0
elif cnt<miin:
return -3
elif cnt>maax:
return -2
elif pwd[0] in forbid:
return -1
else:
if cnt in (-3,-2,-1):
return cnt
else:
return passwordCheck( pwd[1:] , cnt+1 )
mess = 'Please enter a password with no vowels in it: '
while True:
x = str(raw_input(mess)).strip()
y = passwordCheck(x)
if y==0: # inexistent string
mess = ('\nSorry, you must enter a password.\n'
'Please do enter a password: ')
elif y==-1: # string contains a vowel
mess = ('\nSorry, that is not a valid password.\n'
'Your password cannot contain any vowels.\n'
'Please enter a different password: ')
elif y==-2: # string too long
mess = ('\nSorry, the password must have at most %d characters.\n'
'The string you entered has %d characters.\n'
'Please, enter a new shorter password: ' % (maximum,len(x)))
elif y==-3: # string too short
mess = ('\nSorry, the password must have at least %d characters.\n'
'The string you entered has %d characters.\n'
'Please, enter a new longer password: ' % (minimum,len(x)))
else: # success
print ('\nCongratulations, you have entered a valid password!\n'
'You are now able to log on to the system with these credentials.')
break
# EXECUTION
check_password('aeiou',5,12)