Why is Python exiting the while loop without fullfilling all the conditions? - python

I am coding a password checker for an assignment. Here are the requirements:
At least 2 letter between [a-z] and 1 letter between [A-Z]. At least 1 number between [0-9]. At least 1 character from [?$##]. Minimum length 10 characters. Maximum length 14 characters. Moreover, in case of invalid password, the program should keep on asking for new password unless it validates it successfully.
For some odd reason, my code ignores the while loop conditions and jumps out of it after completing the for loop. What am I doing wrong and how could I fix this? Any help is appreciated!
import string
#password
password = input("Enter a password that has at least two lower case letter, one upper case letter, one number between one and nine, and one of the following characters: '?$##.'")
#requirements
ll = list(string.ascii_lowercase)
ul = list(string.ascii_uppercase)
nums = ["1","2","3","4","5","6","7","8","9"]
char = ["?","$","#","#"]
#counters
llcounter = 0
ulcounter = 0
numscounter = 0
charcounter = 0
while llcounter < 2 or ulcounter < 1 or numscounter < 1 or charcounter < 1:
if len(password) > 10 and len(password) < 14:
for x in password:
if x in ll:
llcounter += 1
elif x in ul:
ulcounter += 1
elif x in nums:
numscounter += 1
elif x in char:
charcounter += 1
else:
password = input("Your password has not met the requirements, please try another one.")

well that is because your nested loop logic is flawed. it will keep iterating through the for loop and never checks the while loop conditions. you want the for loop iteration on the outside and break outside when the while conditions are met
for ...:
while ...:
...
break

password = input( ... first prompt ... )
while True:
set all counters = 0
for x in password:
if x in ll:
...etc, just like above...
if llcounter >= 2 and ulcounter and numscounter and charcounter:
break
password = input ( ... second prompt ... )

You need to look up Validate input. You have interleaved steps of your logic. The basic structure is:
valid_pwd = False
while not valid_pwd:
password = input("Enter a password ...")
# Make *one* pass to validate the password.
# Count each type of character;
...
# Also check the length
length_valid = 10 < len(password) < 14
chars_valid = (
ll_count >= 2 and
lu_count >= 1 and
...
)
valid = length_valid and chars_valid
if not valid:
print("Invalid password")
Does that get you going?

When coding in Python you should always try to find the most Pythonic way to implement your idea, namely by making the most of the language's potential to write concise, clear and functional code.
In your case you have redundant code in several places, especially that while loop with so many counters is pretty confusing.
Also, in order to maintain an active input session for the user, you should put the prompt inside the while loop, otherwise the password will always be the same entered for the first (and only) time making the loop itself rather pointless.
For example, here's how you might implement this password check. I commented on the code to try to explain what it's actually doing.
import string
ll = list(string.ascii_lowercase)
ul = list(string.ascii_uppercase)
nums = list(string.digits)[1:] # List of digits except 0
sc = ["?","$","#","#"]
# while True meaning keep prompting forever until password requisites are satisfied.
# This can be changed with a counter to exit the loop after a certain number of attempts.
while True:
password = input("Enter a password that has blablabla...") # Prompt the user at every iteration of the loop.
# The following if block merges all your conditions in the same place avoiding hyper-nested
# conditions that are always confusing and kind of ugly.
# The conditions are based on list comprehension
# (see py docs, since its a super cool feature that is the ultimate tool for conciseness).
if (len([char for char in password if char in ll]) >=2 and
[char for char in password if char in ul] != [] and
[char for char in password if char in nums] != [] and
[char for char in password if char in sc] != []):
print(f" Your new password is: {password}")
break # break interrupts the endless loop as soon as a valid password is entered
else:
print("Your password has not met the requirements, please try another one.")

Related

While loop using strings and if statements

Prompt for python program:
5.16 LAB: Password modifier
Many user-created passwords are simple and easy to guess. Write a program that takes a simple password and makes it stronger by replacing characters using the key below, and by appending "!" to the end of the input string.
i becomes 1
a becomes #
m becomes M
B becomes 8
s becomes $
Ex: If the input is:
mypassword
the output is:
Myp#$$word!
Hint: Python strings are immutable, but support string concatenation. Store and build the stronger password in the given password variable.
My code so far:
word = input()
password = ''
i = 0
while i < len(word):
I'm really just confused about changing certain characters in a string using a while loop. I was also trying to use if statements. While loops are hard for me understand. I don't know where to start.
You're doing fine. While loops have this format:
while (condition) == True:
# do this
In your case, you will want to put i += 1 at then end of your loop so it doesn't go on forever, like this:
while i < len(word):
# your code here
i += 1 # this adds 1 to i
# so eventually it will be equal to the length of word, ending the loop
As for if statements, you could try this:
while i < len(word):
if word[i] == 'i':
password += '1'
i += 1
The if statements will only work on the values you want to change, so add an else statement to act as a default.
while i < len(word):
if word[i] == 'i':
password += '1'
else:
password += word[i]
i += 1
Now, if you get a normal letter, like h, it will add it to the password.
Hope this helps you get started!

One iteration is being wasted, and not getting proper output. (Python)

I am beginner in python and trying to make a simple game in which the user has to guess the word/name by inputting characters of that word/name. The program will generate stars of the word length which the user has to guess.
When the user will input a character, the position of that character in stars will be changed to that character. For example, The word is my name "Vishwas", the program will generate 7 stars as the length of my name is 7, *******, when user will input i the output will be Correct *i***** like this.
Now the problem is my name has two 's' in it, the program is okay till 2 's' but when we input third 's' as input it just wastes that iteration, I want here output as "Incorrect" which I just don't know how to fix here otherwise all the code is okay.
Also, tell what function to use to let the program wait till the user inputs a character as C++ has getch function right now I have used time function.
import time
print("\t\t\t\t\t\t\tWelcome to name guessing game")
name = "shahzaib"
LengthOfWord = len(name)
stars = []
for x in range(LengthOfWord):
stars.append("*")
stars = ''.join(stars)
print(stars)
print("Enter a character")
chance = 2
y=0
LOW=LengthOfWord
while y < LOW:
if chance<0:
print("Game Over")
break
chr = input()
chr = chr.lower()
count = 0
for x in range(LengthOfWord):
if chr[0] == name[x]:
if stars[x] == name[x]:
continue
else:
stars = list(stars)
stars[x] = chr[0]
stars = ''.join(stars)
print("Correct\n",stars)
if stars == name:
print("Congratulations you won")
break
count+=1
if count == LengthOfWord:
print("Incorrect\n",chance,"Chance(s) left\n",stars)
chance -= 1
LOW=LOW+1
y+=1
time.sleep(3)
The program is pretty simple I think it should be easily understandable.
Your logic is too much complex, you don't have to use any time class to wait for user to input, in python we use input() simple. It will wait till infinity for user to input something.
This can be done simply like this:
name = 'shahzaib'
chances = 3
stars = ['*' for _ in name] # I kept it as a list so that we can replace * with char
print("\t\tWelcome to name guessing game")
# while there are chances and user hasn't guessed the whole name
while chances > 0 and '*' in stars:
user = input("\nEnter Character: ").lower()
# If correct
if user in name:
index = name.find(user) # find the first occurence of that char in name
name = name.replace(user, '.', 1) # now replace that char with some special character like '.'
stars[index] = user # replace the value in the stars list so that we can show it to the user
print("Correct\nName: " + ''.join(stars))
else:
chances -=1
print("Incorrect, {} chances left.".format(chances))
Your problem is when you have more than 1 occurrence of the same character in name. This problem arose because of your logic.
The solution as you can see is to replace the occurrence of the character with some special letter like . , :, ; etc, that will not be used in a name. This will also make the program more elegant as you will be guessing the character from left to right.
Ask me anything if you feel confused about the code.

comparison within loop while maintaining value

I am trying to make a python program that
1. compares the first and last letter of a word
2. tell whether the words inputted to the program are in alphabetical order
e.g.) alaska baobab cadillac => would pass
e.g.) alaska baobab greg => would not pass
my code is shown below
num_words = int(input())
while num_words > 0:
my_word = str(input())
num_words -= 1
alphabet_order = ord(my_word[0].lower())
if my_word[0].lower() != my_word[-1].lower() or alphabet_order != ord(my_word[0].lower()):
print(my_word)
break
alphabet_order += 1
if alphabet_order == ord('z') + 1:
alphabet_order = ord('a')
else:
print('no mistake')
Hi everyone on stack.
I am pretty new to programming and I am starting to find assigning variables within a loop very cumbersome.
It seems like my variable alphabet_order keeps getting renewed every time when the loop takes in a new input.
What would be a great way to steadily increase the alphabet_order variable by 1 while only renewing ord(my_word[0]) every loop?
Few notes, while loops are good for when you don't know how many times you are going to loop. for loops are good for when you know how many items you are looping. In this case we have a known number of words we are to check so using a for loop makes more sense. This way we don't need to take an input on telling us how many words we expect.
Also your code wasn't dealing with the words you were dealing with the sentence, so instead you should split() your input by the space to get a list of the words to operate on. for loops can iterate through a list which is useful for us.
Note that for loops also can take an else, the else section runs after the for loop is finished all the elements it's iterating through and we know that if the for is finish all the words in the list, then the else section will kick in. If we break out, then the else doesn't run.
The rest you more or less had it, just need a starting ord('a') would have made life easier.
my_word = input() #take a sentence such as alaska baobab cadillac
current_ord = ord('a')
for each in my_word.split(' '):
if each[0].lower() != each[-1].lower() or current_ord != ord(each[0].lower()):
print(f"bad word {each}")
break
current_ord += 1
if current_ord == ord('z') + 1:
current_ord = ord('a')
else:
print('no mistake')
Maybe this is helpful to you. Instead of initializing it inside the loop, declare it outside the loop and assign it differently based on the conditions.
Tip: having while num_words > 0 is redundant because it will terminate automatically when it hits 0 as it is treated as False. And there is no need to convert int to a str type as it is str by default.
num_words = int(input("Enter a number"))
alphabet_order = None
while num_words:
my_word = input("Enter a word")
num_words -= 1
if alphabet_order is None: # happens only once
alphabet_order = ord(my_word[0].lower())
if ord(my_word[0].lower()) >= alphabet_order:
print('ok')
alphabet_order = ord(my_word[0].lower()) # update alphabet_order
else:
print('not ok EXITING')
break # closing loop

Making a valid password checker. Can not get my program to get through the if conditions to print a valid password

I have been assigned the following exercise as homework:
Some Web sites impose certain rules for passwords. Write a function that checks whether a string is a valid password. Suppose the password rules are as follows:
A password must have at least eight characters.
A password must consist of only letters and digits.
A password must contain at least two digits.
Write a program that prompts the user to enter a password and displays valid password if the rules are followed or invalid password otherwise.
I know there's a more efficient and proper way of doing this but i'm just starting out so I don't necessarily need to be those right now. Just want to finish this question.
The counter/ accumulator works and I don't get any errors but I can not fulfill the if condition correctly so that this program prints "valid password"
password = str(input("Enter in a password to be checked: "))
def valid_password_checker(password):
from string import ascii_lowercase as alphabet
digits = '0123456789' # creates a string of digits
digit = 0 # acc for digits
length = 0 # acc for length
for char in password: # calls on each character in string
if char in alphabet:
length += 1
if char in digits:
digit += 1
if digit >= 2:
flag = True
if length >= 8 and digit is True:
print("valid password")
else:
print("Password does not contain enough characters or digits.")
else:
print("Password does not contain enough digits.")
valid_password_checker(password)
The problem with your existing code is that the variable digit is a number, and therefore doing digit is True as you have done in your if statement, always return False. If you remove digit is True, then your existing solution will work. Take a look however at my version:
def valid(password):
digits = 0
characters = 0
for char in password:
if char.isalpha():
characters += 1
elif char.isdigit():
digits += 1
characters += 1
if characters >= 8:
if digits >= 2:
print("Password is valid")
else:
print("Password doesn't contain enough digits")
else:
print("Password doesn't contain enough characters")
I have made the following modifications from your original:
Used the built-in function str.isdigit() for checking if a character is a digit.
Used the built-in function str.isalpha() for checking if a character is a letter of the alphabet
Moved everything but the counting operations outside of the for loop, so that the function doesn't print multiple things
If you want, you can undo the first two changes, if you're worried about your teacher knowing you asked for help. However, I wouldn't turn in the solution that prints "Password doesn't contain enough digits" as many times as there are characters in the inputted password.
you can write something like this:
password = str(input("What is the password that you want to validate: "))
def get_digits(password):
return [i for i in password if i.isdigit()]
numbers = ''.join(get_digits(password))
if (len(password) < 8) or (len(numbers) < 2):
print(password, "is an invalid password")
else:
print(password, "is a valid password")
nice and simple.

python password checker: numbers and symbols

I'm new to python and I'm having a problem. I need to check a password on its upper, lower, numbers and symbols. It needs 1 of each class and the whole password needs to be longer then 6 characters. I have upper and lower case so far. raw_input inputs as a string so how can I then check for numbers and symbols in that string?
My code so far:
p = raw_input(("plz enter a password to check it's strength"))
if len (p) <= 6:
if p.isupper() or p.islower() or int(p):
print"This is a weak password "
elif len(p) > 6 and len(p) <26:
if p.isupper() or p.islower() or isdigit():
print "wea2k"
else:
print "good"
So what I need to know is how to check the input for numbers and symbols.
Try taking the requirements one at a time.
has_upper = False
for char in p:
if char.isupper():
has_upper = True
break
Repeat this for lower case and digits.
For special characters, use the same type of loop, but change the if to something like this:
if not (char.isupper() or char.islower() or char.isdigit()):
At the end, if all four flags are true, then you have a strong password; otherwise, it's weak.
Can you finish the coding from there?
Just so you know, there are ways to code this that are far more "Pythonic" -- that use the language's style much better. For instance:
has_upper = reduce(lambda a, b: a or b.isupper(), [_ for _ in p], False)
... replaces the entire 5-line block that I gave you.
Try this:
p = raw_input(("plz enter a password to check it's strength"))
upper_case = 0
lower_case = 0
number = 0
symbol = 0
for i in p:
if i.isupper():
upper_case += 1
elif i.islower():
lower_case += 1
elif i.isdigit():
number += 1
else:
symbol += 1
if len (p) <= 6:
print"This is a weak password "
elif upper_case > 0 and lower_case > 0 and number > 0 and symbol > 0:
print "Good"
else:
print "Too Weak"

Categories