Python problem with while loop on password check - python

I am just getting into programming recently and still many things are not clear to me. However in this code I just don't understand the logic. I premise that I don't want to use either import or def(), but I want to understand how I have to reason to make this piece of code work.
A User enters the pwd, and I want there to be a check for numbers and letters that must be present.
The first while is to avoid empty pwd; at this point I dismember the pwd and check for letters and numbers.
Enter the second while and here if I enter only numbers or only letters it works but if I put numbers and letters it keeps staying in the loop.
I tried putting a break (is commented) but it doesn't work.
If anyone can make me understand what I am doing wrong I will be grateful.
Regards
pwd = input("Enter password.\n")
# This loop is used to check if the User has not typed in the password.
while len(pwd) == 0: # Enter the loop when it finds the pwd box empty
print("You left the password box empty.\n")
pwd = input("Enter the password.\n") # Query the password
n = ''.join(filter(str.isdigit, pwd))
char = pwd.isalpha()
num = n.isdigit()
# print(char, num)
# Control loop so that there are letters and numbers
while (char== False and num == True) or (char== True and num == False):
n = ''.join(filter(str.isdigit, pwd))
char= pwd.isalpha()
num = n.isdigit()
print("Attention the password must contain numbers and letters.")
pwd = input("Enter password again.\n") # Prompt for password
# break
if (char== True and num == True):
break
print("Password contains numbers and letters. Accepted!")
PS: Instead of While I tried using if, but if the User keeps putting either only numbers or only letters I have no way to go back as I can with While.

First, Issue you are getting is because of the line
char = pwd.isalpha()
At this point char will always be False, unless pwd is only alpha. So, when you enter a password that is mix of alpha and number example 123asd, char will always be False as you are directly using isalpha() method on pwd. What you want to do here is use same approach you used to check numbers. That mean adding the line below,
c = ''.join(filter(str.isalpha, pwd))
before
char = c.isalpha()
This way you are filtering all the alpha out.
Second, inside your 2nd while loop. You need to move the lines
print("Attention the password must contain numbers and letters.")
pwd = input("Enter password again.\n") # Prompt for password
on top, before doing all those alpha and digit filters. So, that you will always have the latest value stored in the pwd.
[OPTIONAL]
Furthermore, using your same approach, I would suggest to refactor your code as following.
pwd = input("Enter password.\n")
num = ''.join(filter(str.isdigit, pwd))
char = ''.join(filter(str.isalpha, pwd))
while not pwd or not num or not char:
if not pwd:
print("You left the password box empty.")
else:
print("Attention the password must contain numbers and letters.")
pwd = input("Enter password again.\n")
num = ''.join(filter(str.isdigit, pwd))
char = ''.join(filter(str.isalpha, pwd))
print("Password contains numbers and letters. Accepted!")

Related

Confused about if statements and functions

I'm very familiar with the random module but I always stumbled when it came to functions. How do I make a function only occur if it meets a certain condition? It gives me no output when im trying to validate my answer...
choice = input ("Which type of password would you like to generate? \n 1. Alphabetical \n")
if choice == 1:
characters = list(string.ascii_letters)
def generate_random_abc_password():
length = int(input("Enter password length: "))
random.shuffle(characters)
password = []
for i in range(length):
password.append(random.choice(characters))
random.shuffle(password)
print("".join(password))
generate_random_abc_password()
Seems like the most common mistake among beginners. When you use an input() function, it will return you some number/text/float or decimal number but in string type. For example
x = input("Enter your number")
# If i would input 2, my x variable would contain "2"
# 3 => "3"
# 550 => "550" and so on...
To avoid such a problem and to store your value in proper type, you need to wrap your input with int() function, as shown below
x = int(input(("Enter your number"))
# From now, whenever i prompt any number from my keyboard, it will
# be an integer number, which i can substract, add, multiply and divide.
As simple as it is. Happy learning!
You should convert the input to integer as by default the data type for input is string.
Alternatively rather than changing input data type you can compare it with the str(1) or change if choice == 1: to if choice == '1':
You can try using :
import string
import random
choice = int(input ("Which type of password would you like to generate? \n 1. Alphabetical \n"))
if choice == 1:
characters = list(string.ascii_letters)
def generate_random_abc_password():
length = int(input("Enter password length: "))
random.shuffle(characters)
password = []
for i in range(length):
password.append(random.choice(characters))
random.shuffle(password)
print("".join(password))
generate_random_abc_password()
The above code will result in :
Which type of password would you like to generate?
1. Alphabetical
1
Enter password length: 10
MEQyTcspdy
The problem here is that you've defined the characters variable in your if block. That is your function is not aware of of the variable that is why you should pass the characters variable as a input to the function the code should look like
choice = input ("Which type of password would you like to generate? \n 1. Alphabetical \n")
if choice == 1:
characters = list(string.ascii_letters)
def generate_random_abc_password(characters):
length = int(input("Enter password length: "))
random.shuffle(characters)
password = []
for i in range(length):
password.append(random.choice(characters))
random.shuffle(password)
print("".join(password))
generate_random_abc_password(characters)
A function works like an isolated piece of code it takes it's own inputs and returns it's own outputs or does it's stuff.
As well as the input isn't casted to an int as the above mentioned answer says...

How to check if string has lowercase letter, uppercase letter and number [duplicate]

This question already has answers here:
How to detect lowercase letters in Python?
(6 answers)
Closed 4 years ago.
I need to make a simple password checker, it needs to check if the string has at least one lowercase letter, one uppercase letter and one number.
here's what i have
passwd = raw_input("enter your password: ")
upper = 0
lower = 0
number = 0
while len(passwd) < 7 and upper <= 0 and lower <= 0 and number <= 0:
print 'start'
for x in passwd:
if x.isupper()==True:
print 'upper'
upper+=1
elif x.islower()==True:
print 'lower'
lower+=1
elif x.isalpha()==False:
print 'num'
number+=1
print ('password not complex enough')
upper = 0
lower = 0
number = 0
passwd = raw_input('please enter password again ')
those random looking prints are for debugging so i can see where it's reaching.
and what looks like is happening is that it only checks the first condition, the length condition and then leaves the loop.
here's a sample of what is happening
enter your password: pA1
start
lower
upper
num
password not complex enough
please enter password again password
why is it only checking the length condition? what did i do wrong?
You can simplify the whole logic by utilising unicodedata.category to collect what category of a character is and then check to see if all expected are present, eg:
import unicodedata
is_valid = (
len(password) >= 7 and
{'Ll', 'Lu', 'Nd'}.issubset(unicodedata.category(ch) for ch in password)
)
You have some problems with your checking logic. First of all you re-set your control variables before the while condition could check them. Furthermore you used and to test if all conditions are true, while or is what you should be using. If you want to keep the basic structure of your code, the best way to go is to use only True in your while statement and then break the loop once all conditions are fulfilled. Of course, as shown in the other answers, there are much more compact ways to check that all conditions are fulfilled.
passwd = raw_input("enter your password: ")
upper = 0
lower = 0
number = 0
while True:
for x in passwd:
if x.isupper()==True:
print 'upper'
upper+=1
elif x.islower()==True:
print 'lower'
lower+=1
elif x.isalpha()==False:
print 'num'
number+=1
if len(passwd) < 7 or upper <= 0 or lower <= 0 or number <= 0:
print ('password not complex enough')
passwd = raw_input('please enter password again ')
upper = 0
lower = 0
number = 0
else:
break
print 'final password:', passwd
Output:
enter your password: pA
lower
upper
password not complex enough
please enter password again pA1ghlfx78
lower
upper
num
lower
lower
lower
lower
lower
num
num
final password: pA1ghlfx78
If a password must consist of ASCII letters and numbers only, then the most efficient approach would be to use sets:
from string import ascii_lowercase, ascii_uppercase, digits
def is_valid(password):
if len(password) < 7:
return False
password_set = set(password)
return not any(password_set.isdisjoint(x)
for x in (ascii_lowercase, ascii_uppercase, digits))
If unicode characters are allowed, you could use any():
def is_valid(password):
return (len(password) >= 7 and
any(c.islower() for c in password) and
any(c.isupper() for c in password) and
any(c.isdigit() for c in password))
May this is helpful for you.I use sum(1 for c in the string if c.islower()) to find the total number of lowercase. and same way to find the total number of uppercase and digit.len(string) to find length of string.
string=input()
if ((sum(1 for c in string if c.islower())>=1) and (sum(1 for c in string if
c.isupper())>=1) and (sum(1 for c in string if c.isdigit())>=1) and (len(string)>=7)):
print("Password is complex")
else:
print ("Password not complex enough")

How to find the mean of a list

I'm very new to python and trying to write some code so that the user enters something. If it's an integer it's sorted into the Numbers list, if it's a string it goes into the String list.
I want to be able to find the mean of all the numbers that are in the list and print out the result.
And in the String section I want to be able to print out everything within the string and its length.
User types 'save' to exit and if input is valid that's caught.
Numbers = []
String = []
while(True):
user_input = input("What's your input? ")
if user_input == "save":
break
elif user_input.isdigit():
Numbers.append(user_input)
for i in range(len(Numbers)):
Numbers[i] = int(Numbers[i])
print(sum(Numbers)/len(Numbers)
elif isinstance(user_input, str):
String.append(user_input)
print(String)
print (len(String)-1)
else:
print("Invalid input.")
break
#use isalpha to check enterted input is string or not
#isalpha returns a boolean value
Numbers = []
String = []
while(True):
user_input = input("input : ")
if user_input == "save":
break
elif user_input.isdigit():
Numbers.append(int(user_input))
print(sum(Numbers)/len(Numbers))
elif user_input.isalpha():
String.append(user_input)
print(String)
print (len(String))
else:
print("Invalid input.")
break
There is good thing called statistics.mean:
from statistics import mean
mean(your_list)
You are using Length, which has not been defined. I think what you wanted was
print(sum(Numbers)/len(Numbers))
and you probably don't want it inside the loop, but just after it (although that might be another typo).
I found other more convenient way to produce the mean: Use statistics model and output the mean.
#import useful packages
import statistics
#Create an empty list
user_list = []
#get user request
user_input = input("Welcome to the average game. The computer is clever enough to get the average of the list of numbers you give. Please press enter to have a try.")
#game start
while True:
#user will input their number into a the empty list
user_number = input("Type the number you want to input or type 'a' to get the average and quit the game:")
#help the user to get an average number
if user_number == 'a':
num_average = statistics.mean(user_list)
print("The mean is: {}.".format(num_average))
break #Game break
else:
user_list.append(int(user_number))
print(user_list)

Password Checker

I have created a password checker which generates a random character and compares it until all the characters are the same. But as it rolls through it repeats the character multiple times. Is there a way of making it so the character doesn't repeat, possibly putting the characters into a list? I could then use the
list.del()
function to stop it repeating. Here is my code:
import string
import random
import time
print('Welcome to the password checker')
characters = string.ascii_lowercase + string.digits + string.ascii_uppercase + ' .,!?;:`"+/*()##$&_-='
password = input("Enter your password: ")
tryFirst = ''.join(random.choice(characters) for i in range(len(password)))
trySecond = ''
Finished = False
attempt = 0
while Finished == False:
print("{}) {}".format(attempt,tryFirst))
trySecond = ''
Finished = True
for num in range(len(password)):
if tryFirst[num] != password[num]:
Finished = False
trySecond += random.choice(characters)
else:
trySecond += password[num]
attempt += 1
tryFirst = trySecond
time.sleep(0.05)
print("Password found! That took {} attempts".format(attempt))
if attempt < 100:
print("Your password isn't safe")
elif attempt < 250:
print("Your password is quite safe, could do with improvement")
elif attempt < 400:
print("Your password is adequately safe")
elif attempt < 600:
print("Your pasword is safe")
Quick Answer
First, as others already have mentioned, your method will not give you the answer you seek. For example, inputting example as a first password and Qm2cl?X as a second. Your program would return a similar result although they are obviously not equally strong passwords. The first can be found in a dictionary while the second is much harder to guess (it possesses more randomness).
To answer your question, you could use the same random character for all positions in your word each iteration. Then you can safely pop each checked character off the characters list. Here is a possible implementation:
import string
import random
import time
print('Welcome to the password checker')
characters = string.ascii_lowercase + string.digits + string.ascii_uppercase + \
' .,!?;:`"+/*()##$&_-='
characters = list(characters)
random.shuffle(characters)
password = input("Enter your password: ")
tryFirst = characters.pop() * len(password)
Finished = False
attempt = 0
while not Finished:
print("{}) {}".format(attempt, tryFirst))
trySecond = ''
Finished = True
try:
char = characters.pop()
except IndexError:
print 'No more characters to check'
for num in range(len(password)):
if tryFirst[num] != password[num]:
Finished = False
trySecond += char
else:
trySecond += password[num]
attempt += 1
tryFirst = trySecond
time.sleep(0.05)
print("Password found! That took {} attempts".format(attempt))
if attempt < 100:
print("Your password isn't safe")
elif attempt < 250:
print("Your password is quite safe, could do with improvement")
elif attempt < 400:
print("Your password is adequately safe")
elif attempt < 600:
print("Your password is safe")
Fundamental Problem
A problem however is that you check each character individually, which would be impossible to do for a real hacker. By doing this, you reduce the problem difficulty of finding the correct password significantly. For example, in your case you have 83 different characters in your characters list. By checking each character individually, you will never need more than 83 attempts to get the correct password (if you remove your duplicates problem). If you would only be able to check a complete password instead of characters individually, as would be the case in a live situation, the number of attempts to find the correct password is much higher, being 83^password_length/2. For example, you would already need 3444 attempts on average to guess a password of two characters and 285893 for a password of three characters.
So, if you would really like to know the number of attempts a primitive brute-force algorithm would need to guess a given password composed of the 83 characters in your characters list, just use this formula: 83^password_length/2.
But be warned that this does not take into account that humans tend to pick passwords with a certain structure and thus with a certain predictability. Password cracking programs exploit this weakness by using for example dictionary attacks and rainbow tables. Thus the actual number of attempts a cracking program would need may be much lower than this formula would suggest.

MasterMind problems

I've made the game Mastercode and I am having troubles getting the computer to tell the user which numbers they got correct and incorrect.
My code is listed below, along with the attempt I used for getting the computer to print the correct answers. If someone could tell me what I am doing wrong and point me in the right direction, that would be great.
import random
def masterMind():
Password = "%05d" % random.randint(0, 99999) #the computer chooses 5 random numbers
for tries in range(10):
userGuess = raw_input("Guess my 5 digit password to access the treasure:")
if Password == userGuess:
print "Win on the %d try" % (tries + 1)
hint(password, userGuess)
break #terminates the ongoing loop and executes next statement
print "answer was:", Password #tells computer to print the password
def hint(password, guess): #function of the hints
for i in range(5): #the range within the five integers
if guess[i] == password[i]: #if the user's integer aligns with computers integer then an 'x' should appear
print 'x',
continue
if guess[i] in answer: #if don't have corresponding number then an 'o' will appear
print 'o',
I think you really need to check for black and white pegs in separate parts of hint(). This allows you to REMOVE something that "matched as black", and not [incorrectly] score additional whites for it.
Using lists, this can be implemented as such:
def hint(password, guess):
# convert the strings to lists so we can to assignments, below
password_list = list(password)
guess_list = list(guess)
# check for black (correct number in correct position)
for i in range(5): #the range within the five integers
if guess_list[i] == password_list[i]:
print 'x',
# punch in some non-possible value so we can exclude this on the check for white
guess_list[i] = None
password_list[i] = None
# check for white (correct number in wrong position)
for i in range(5):
if guess_list[i] == None:
continue
if guess_list[i] in password_list:
print 'o',
# remove this from the password list, so that a given
# password digit doesn't incorrectly count as multiple white
password_list.remove(guess_list[i])
# or this would work, too:
#password_list[password_list.index(guess_list[i])] = None
print
One you have more Python experience you might find more concise ways to do this with set() objects or Counter() objects... but see if you can see WHY the above works.
Here's my test case: I set the password to "12345", then did these tests:
Guess my 5 digit password to access the treasure:11111
x
Guess my 5 digit password to access the treasure:21777
o o
Guess my 5 digit password to access the treasure:77721
o o
Guess my 5 digit password to access the treasure:21774
o o o
Guess my 5 digit password to access the treasure:21775
x o o
Guess my 5 digit password to access the treasure:14355
x x x o
Guess my 5 digit password to access the treasure:12345
Win on the 7 try
Is that the result you are looking for?
First, you should move the hint call out of the if block (probably it's not a good idea to hint a user only when he/she got the password right):
if Password == userGuess:
print "Win on the %d try" % (tries + 1)
break #terminates the ongoing loop and executes next statement
hint(Password, userGuess)
By the way you were calling hint as hint(password, userGuess). Python names are case-sensitive and you should call it like this: hint(Password, userGuess). Well, really you should rename the Password variable to password - common Python convention is to use lowercase in the variable names.
Second, you have undefined variables in the hint function. I think this function should look like this:
def hint(password, guess): #function of the hints
for i in range(5): #the range within the five integers
if guess[i] == password[i]: #if the user's integer aligns with computers integer then an 'x' should appear
print 'x',
else:
print 'o',
With these changes your code works: I got 18744 password on the 10th try.
About the masterMind() part : The hint() call is executed at the wrong place. Also it uses password and not Password as a parameter
def masterMind():
Password = "%05d" % random.randint(0, 99999) #the computer chooses 5 random numbers
for tries in range(10):
userGuess = raw_input("Guess my 5 digit password to access the treasure:")
if Password == userGuess:
print "Win on the %d try" % (tries + 1)
break #terminates the ongoing loop and executes next statement
else :
hint(Password, userGuess)
print "answer was:", Password #tells computer to print the password
About the hint part :
answer isn't defined anywhere, I think you meant password.
I'm not sure you can work with integers like that, but it'll be fine if you convert them to strings.
Finally the algorithm structure doesn't work well. If a number of the guess is at the right place, the guess function will both echo x and o.
You should use a if ... elif structure, and then you could add a else clause to notify the user that this number isn't in the password at all !
Try to rewrite your hint() function with these indications, but if you need more help, here's a working solution.
def hint(password, guess): #function of the hints
for i in range(5): #the range within the five integers
if str(guess)[i] == str(password)[i]: #if the user's integer aligns with computers integer then an 'x' should appear
print 'x',
elif str(guess)[i] in str(password): #if don't have corresponding number then an 'o' will appear
print 'o',
else:
print '_', # _ is displayed if the number isn't in the password at all.
Also, it would be nice to check that the user's guess has exactly five digits. If it has less than five digits, there'll be an error.

Categories

Resources