if block doesn't trigger, even when it should - python

Clearly I'm doing something wrong here...
accountManager = open("accountManager.txt","r")
userNameInvalid = True
while userNameInvalid == True:
userName = input("Username (this is public): ")
userNameLine = 0
for line in accountManager.readlines():
if (((userNameLine % 6) == 2) and (userName == line)):
print("The username \"" + userName + "\" taken, please choose another one.")
userNameInvalid = True
break
userNameInvalid = False
userNameLine += 1
For context: accountManager is a txt file (currently open in 'r' mode) that looks like the following:
*empty line*
Real name 1
Username 1
Email 1
Notes 1
*empty line*
*empty line*
Real name 2
Username 2
Email 2
Notes 2
*empty line*
*empty line*
Real name 3
Username 3
Email 3
Notes 3
*empty line*
As you can see, it comes in little "chunks" of 6 lines, the number of which would be unknown.
What I want it to do:
Only when the input is "Username 1", "Username 2" or "Username 3", the if statement should trigger.
What happens:
if statement never runs
UPDATE:
If statement now runs, but now, if you at first enter a taken username, it will get stuck in the while loop and never get out... Why?

It's because of the condition userName == line is never true. When you read a line using f.read(), or f.readlines(), each line is terminated with the new line character \n. So, for example, instead of "Username 1", the line will be "Username 1\n". A simple way to solve this is to append "\n" to the comparison string userName as the following.
userName = input("Username (this is public): ") + "\n"
Also, f.readlines() returns an empty list if you don't reset the file object. You can get stuck in the while loop as the result. You can fix it using f.seek(0), but instead of re-reading the file multiple times, save the list of lines for re-use.
accountManager = open("accountManager.txt","r")
userNameInvalid = True
lines = accountManager.readlines()
while userNameInvalid == True:
userName = input("Username (this is public): ")
userNameLine = 0
for line in lines:
if userNameLine % 6 == 2 and userName == line:
print("The username \"" + userName + "\" taken, please choose another one.")
userNameInvalid = True
break
userNameInvalid = False
userNameLine += 1

As you have it the code is hard to follow. I would restructure the code by first reading all the data into a more usable format, and only then validate it. You can take each section of user data and place them into a list of small dicts.
Using a while loop and iter/next you could pretty easily parse the data. You should also strip the line to remove extra whitespace:
raw_data = iter(accountManager.readlines())
user_data = []
try:
while True:
next(raw_data) # clear blank line
user_data.append(
{
'real_name': next(raw_data).strip(),
'username': next(raw_data).strip(),
'email': next(raw_data).strip(),
'notes': next(raw_data).strip(),
}
)
next(raw_data) # clear blank line
except StopIteration: # no more values in raw_data iter
pass # do nothing, we expect this
Once you have the data, I would use a set to check for duplicates:
username_invalid = False
usernames = set()
for data in user_data:
username = data['username']
if username in usernames:
print(
f'The username "{username}" '
'is taken, please choose another one.'
)
username_invalid = True
break
usernames.add(username)

Related

Python - Read each line of text file and pass each line to variable

I am attempting to implement a simple password checker which will allow the user to open a text file that contains generated passwords and check them against a list of criteria to see if the password is strong or weak. It should then output the password with the result of whether it is strong or weak.
With the current solution I can get the list of passwords to print, but when the check as to whether the password is strong or not, only one result is shown. I am attempting for the output to be the password that is generated with the result e.g. Randompassword123 - This is a weak password.
Below is the code I am currently using:
def multiplestrength(): # password strength check function
textfile = filedialog.askopenfilename(initialdir="/home", title = "Select text file to split",filetypes = (("text files","*.txt"),("all files","*.*")))
with open(textfile , mode="r",encoding="utf-8") as my_file:
data=my_file.read()
print(data)
def strongPassword(data):
if passRegex1.search(data) == None:
return False
if passRegex2.search(data) == None:
return False
if passRegex3.search(data) == None:
return False
if passRegex4.search(data) == None:
return False
else:
return True
passRegex1 = re.compile(r'\w{8,}')
passRegex2 = re.compile(r'\d+')
passRegex3 = re.compile(r'[a-z]')
passRegex4 = re.compile(r'[A-Z]')
if strongPassword(data) == True:
print("Strong Password")
else:
print("This is not a strong password")
The output I receive is below
So it appears that only one password is being checked from the list of 5 passwords in the text file. I believe there might need to be a for loop required somewhere for each password to be checked, but I am unsure what way to approach this. Another approach I was thinking would be to insert the passwords from the text file into a list and iterating through this list to get a result for each password. Does this possibly sound like the correct way to approach this?
Any help with this would be greatly appreciated.
Thanks
I have written a solution. I have added many comment for code as description.
Code:
import re
passRegex1 = re.compile(r'\w{8,}')
passRegex2 = re.compile(r'\d+')
passRegex3 = re.compile(r'[a-z]')
passRegex4 = re.compile(r'[A-Z]')
def strong_password(data): # the function name should be snake case
if not passRegex1.search(data): # Use "if not". It is the Pythonic way. It handles False/None/0/""/[] etc...
return False
if not passRegex2.search(data):
return False
if not passRegex3.search(data):
return False
if not passRegex4.search(data):
return False
else:
return True
with open("test.txt", mode="r", encoding="utf-8") as my_file: # Open file for reading
for line in my_file.readlines(): # Read all lines one-by-one
print("\nPassword: {}".format(line.strip())) # Print the current password ("strip" removes the whitespace characters from string).
if strong_password(line): # This statement is True if the "strong_password" function returns True
print("Strong Password")
continue # Get the next element (line of file)
print("This is not a strong password") # Else statement is not needed because the "if" contains a continue
My test file:
asdf
121234
adsf123
asdffdsatre323423
fdggfd2323____,,,**
tt
333345
asdfSDFGRAdsfAERTGRghRGads___++((((FDsaSDfAS4233423524
434
55555
Output:
>>> python3 test.py
Password: asdf
This is not a strong password
Password: 121234
This is not a strong password
Password: adsf123
This is not a strong password
Password: asdffdsatre323423
This is not a strong password
Password: fdggfd2323____,,,**
This is not a strong password
Password: tt
This is not a strong password
Password: 333345
This is not a strong password
Password: asdfSDFGRAdsfAERTGRghRGads___++((((FDsaSDfAS4233423524
Strong Password
Password: 434
This is not a strong password
Password: 55555
This is not a strong password
You could loop through the lines of your file using:
with open(textfile , mode="r",encoding="utf-8") as my_file:
for line in my_file:
# do something with the line, eg:
if strongPassword(line):
# ...
Edit: you might want to use line.strip() instead of line to get rid of the newline characters at the end (\n)

Searching through text files using loops

I am trying to create a very simple piece of code which will search through a text file to see if a username has been registered or not. However I am unsure how to search through the text file to find a match for the username.
Here is my code so far:
NotLoggedIn = False
while NotLoggedIn == False:
username = input("\nplease enter a username or to sign in type '!'")
for next in records:
if username == records:
print("hi")
NotLoggedIn = True
Thanks in advance.
Here is what you can try provided you have a textfile named records.txt since as per your question you need to search through a text file.
f = open("records.txt", 'r')
NotLoggedIn = False
while NotLoggedIn == False:
username = input("\nplease enter a username or to sign in type '!'")
for line in f.readlines():
if username in line:
print("hi, username exists in the file")
NotLoggedIn = True
break
if not NotLoggedIn:
print ("User does not exist in the file")
f.close()
It depends on how you wrote your text file.
if that text file is like this :
username1\nusername2\n
...
Then we can code like this :
f = open("records.txt","r")
m = f.readlines()
f.close()
NotLoggedIn = False
while NotLoggedIn == False:
username = input("\nplease enter a username or to sign in type '!'")
for line in m :
if line.replace("\n","") == username : # removing "\n" from the line
print("hi")
NotLoggedIn = True
break # No need to check others
It is important to be specific.
You shouldn't use "in" to find a username inside of a string, because if you have a username called string then if someone types str , it will be like this :
if "str" in "string"
Witch will be true But it doesn't exist in your text file. So try using "==" operator.

Command only reads first line of text file

I have to make a program in which one of the functions is retrieval of usernames and results from a text file. (All on the same line)
For some reason, when I run it, only the first line is printed out. Why is this ? Also, this only happens when I try to run the program at school (part of an assignment), it prints everything it needs to on my laptop at home. (Python versions are also the same)
Here is my code :
def results():
username = input("Enter username :")
for line in open("resultsfile.txt","r"):
if username in line:
print (line)
elif username not in line:
("No such user")
Also, this is what the text file looks like (without bullet points) :
tud16 CS Easy 2points
ser23 CH Med 4points
tud16 CS Hard 1points
def results():
username = input("Enter username :")
for line in open("resultsfile.txt","r"):
if username in line:
print (line)
else:
print("No such user")
results()
You are iterating over a file but you are printing No such user for every line that does not match the username.
What you should do is evaluate after the loop if one of the lines in the file contained the username. To implement this you could introduce a boolean (found) indicating if a user has been found or not:
def results():
found = False
username = input("Enter username :")
for line in open("resultsfile.txt","r"):
if username in line:
print (line)
found = True
if not found:
print("No such user")

Read line by line from text file

I have this text file that contains:
Ryan#Male#Ryan123#Ryan321#
Lina#Female#Lina123#Lina321#
the order is Name#Gender#username#password.
user = username.get() //from tkinter entry
pass = password.get()
counter = IntVar()
counter = 0
file = open("user.txt", "r")
for login in file:
login = login .split('#')
if user == login [2]:
counter += 1
if pass== login [3]:
counter += 1
file.close()
if counter == 2:
//go to next page
else:
print "wrong username or password!"
this works, but, when I tried to print login[2], it returned;
Ryan123
Lina123
and when I used Ryan as username, I still can login using Lina's password aswell. How can I make it check the content in .txt file row per row?
I mean like, check this row first:
Ryan#Male#Ryan123#Ryan321#
and when the login info is not found, it will proceed to next row.
The password problem is because you never reset counter between lines. But it can be done even more simply without counting conditions:
file = open("user.txt", "r")
for login in file:
login = login.split('#')
if user == login[2] and password == login[3]:
print 'Correct username/password'
break
else:
print 'Invalid username/password'
pass, by the way, is a keyword in Python, so it's a good idea to use something else for your variable name.
You need an "and" condition here, since password and username should match!
he_is_cool = False
for login in file:
login = login .split('#')
if user == login [2] and pass== login [3]:
he_is_cool = True
break
file.close()
if he_is_cool:
//go to next page
else:
print "wrong username or password!"
Note that break will "kill" your loop, when you have identified the user. The program will also work without break.
You are checking two different fields possibly lying on two different lines (e.g. the user matches Ryan and the password matches Lina's).
Normally user and password must both match for a single given user.
So you can get rid of the counters and try with
pwd = password.get()
with open("user.txt", "r") as file:
for login in file:
login = login .split('#')
if user == login[2] and pwd == login[3]:
pass # go to next page, substitute pass on this line!
else:
print "wrong username and password!"

Python read next line from what the user inputs

So basically I have a program which can create a users username and password in a document and search for the password used with the username that is input by the person using the program.
For example:
The programs asks me to input a username I enter: '13'.
Under 13 in the text document is 'sadfsdfsdf'.
I want the program to skip to below the 'Username: 13' and read and print 'Password: sadfsdfsdf'.
note that I have multiple usernames and passwords In the .txt file
u = 'Username: '
Thanks in advance!
def SearchRecordProgram():
while True:
user_search = input("Please enter the username you wish to see the password for: ")
full_user = u + user_search
if full_user in open('User_Details.txt').read():
print(" ")
print ("Username found in our records")
print(" ")
print(full_user)
break
else:
print("Username entered does not match our records")
So, imagining your file is like so:
Username : 13
Password : sadfsdfsdf
Username : 15
Password : Lalalala
You can parse it (with regular expressions) like so:
import re # regular expression module
regex = re.compile("Username :(.*)\nPassword :(.*)")
# read text from file
with open(filePath,'r') as f:
text = f.read()
u_pass = regex.findall(text)
# [(' 13', ' sadfsdfsdf'), (' 15', ' Lalalala')]
user_dict = {u:password for u,password in u_pass}
# {' 13': ' sadfsdfsdf', ' 15': ' Lalalala'}
Now you can get the password of someone by asking for the password of that user :
# given username and password_input
if username in user_dict and user_dict[username] == password_input:
# if username exists and password okay
print "Authentication succeeded."
When you want to open a file, you should almost always use the with statement:
with open('User_Details.txt') as read_file:
# Do reading etc. with `read_file` variable
This will ensure that any errors are being handled correctly and the file is not left open.
Now that the file is open, we need to loop through each line until we find one that matches our username. I hope you know how for loop works:
username = 'Username: 13' # Get this however you want
with open('User_Details.txt') as read_file:
for line in read_file:
line = line.strip() # Removes any unnecessary whitespace characters
if line == username:
# We found the user! Next line is password
And we need to get the next line which contains the password. There are many ways to get the next line, but one simple way is to use the next() function which simply gets us the next element from an iterable (the next line from a file in this case):
username = 'Username: 13'
with open('User_Details.txt') as read_file:
for line in read_file:
line = line.strip()
if line == username:
password = next(read_file)
break # Ends the for loop, no need to go through more lines
Now you have a password and an username, and you can do whatever you want with them. It's often a good idea to have the inputs and outputs outside of your program's logic, so don't print the password right inside the for loop, but instead just receive it there and then do the printing outside.
You might even wanna turn the whole search logic into a function:
def find_next_line(file_handle, line):
"""Finds the next line from a file."""
for l in file_handle:
l = l.strip()
if l == line:
return next(file_handle)
def main():
username = input("Please enter the username you wish to see the password for: ")
username = 'Username: ' + username
with open('User_Details.txt') as read_file:
password = find_next_line(read_file, username)
password = password[len('Password: '):]
print("Password '{0}' found for username '{1}'".format(password, username))
if __name__ == '__main__':
main()
Finally, it's absolutely insane to store anything in this format (not to mention password security stuff, but I get you're just learning stuff), why not do something like:
username:password
markus:MarkusIsHappy123
BOB:BOB'S PASSWORD
This could then easily be converted into a dict:
with open('User_Details.txt') as read_file:
user_details = dict(line.strip().split(':') for line in read_file)
And now to get a password for an username, you'd do:
username = input('Username: ')
if username in user_details:
print('Password:', user_details[username])
else:
print('Unknown user')
Maybe not the pretties, but something like this will work:
with open(users_file, "r") as f:
lines = f.read()
def get_password(user_id):
entries = iter(lines.splitlines())
for entry in entries:
if(entry.startswith("{}:{}".format(prefix, user_id))):
return next(entries)
print "Password:", get_password("13")
def SearchRecordProgram():
while True:
user_search = input("Please enter the username > ")
file = open('User_Details.txt')
usernames = file.readlines() # Read file into list
file.close()
if user_search in usernames: # Username exists
print ('Found Username')
password = usernames[usernames.index(user_search)+1]
print ('Password is: ' + password)
break # Exit loop
else: # Username doesn't exist
print("Username entered does not match our records")
Note that this will not work if a password happens to be a username, e.g:
user1
password1
user2
user3 # This is the password for user3
user3
password3
If you search for "user3" this code will output "user3" as the password for "user3" because it finds the first instance of "user3" (line 4) and then looks to the next line (line 5), which is the next username.
Even worse, if "user3" is the last line in the file, it will end with an error because there are no more lines. You could add a check that the index of the found username is even (i.e. index 0, 2, 4, 8) with this code:
if not usernames.index(user_search) % 2: # Checks the remainder after / by 2.
# If it's 0 then it's an even index.
password = usernames[usernames.index(user_search)+1]
print ('Password is: ' + password)
but there isn't much you can do if this happens.
However, you could manipulate the file of usernames to only have usernames like this:
lst = [0, 1, 2, 3, 4, 5, 6, 7]
print (lst[0::2])
which prints
[0, 2, 4, 6]
So the code could be changed to this:
def SearchRecordProgram():
while True:
user_search = input("Please enter the username > ")
usernames = open('User_Details.txt').readlines() # Read file into list
if user_search in usernames[0::2]: # Username exists
print ('Found Username')
password = usernames[1::2][usernames[0::2]].index(user_search)]
print ('Password is: ' + password)
break # Exit loop
else: # Username doesn't exist
print("Username entered does not match our records")
Here is a breakdown
password = usernames[1::2] # Gets the odd items (passwords)
[ # Get index item. The index returned from searching
# the usernames will be the same as the index needed
# for the password, as looking at just the odd items:
# [0, 2, 4, 6]
# [1, 3, 5, 7] - even has the same index as next odd.
usernames[0::2] # Gets even items (usernames)
].index(user_search)]
# Only searches the usernames. This
# means passwords being the same is not
# an issue - it doesn't search them

Categories