I have this code where the user has to input the name of a file which includes a message and the name of a file where the message must be written after its encrypted via Caesar-Cipher.
I would like to validate the inputs, so that if there's a wrong input, the code won't crash but ask the user for a valid file path until the user inputs it.
I have some familiarity with validation using the while loop, however I couldn't apply it here without ruining other parts of the code.
Any suggestions are appreciated.
def open_file(source_path: str, dest_path: str):
with open(source_path, mode='r') as fd:
while line := fd.readline():
return line
def write_to_file(dest_path: str, line: str):
with open(dest_path, mode='a') as fd:
fd.write(line)
source_path = input("Enter the name of the file including the message: ")
dest_path = input("Enter the name of the file where the encrypted message will be written: ")
MODE_ENCRYPT = 1
def caesar(source: str, dest: str, steps, mode):
alphabet = "abcdefghijklmnopqrstuvwxyzabcABCDEFGHIJKLMNOPQRSTUVWXYZABC"
alpha_len: int = len(alphabet)
new_data = ""
file = open_file(source_path, dest_path)
for char in file:
index = alphabet.find(char)
if index == -1:
new_data += char
else:
# compute first parth
changed = index + steps if mode == MODE_ENCRYPT else index - steps
# make an offset
changed %= alpha_len
new_data += alphabet[changed:changed + 1]
write_to_file(dest_path, new_data)
return new_data
while True:
# Validating input key
key = input("Enter the key: ")
try:
key = int(key)
except ValueError:
print("Please enter a valid key: ")
continue
break
ciphered = caesar(source_path, dest_path, key, MODE_ENCRYPT)
Not quite sure what you meant by not being able to use a while loop, but here is a simple way of checking if the paths exists using pathlib.
from pathlib import Path
while True:
source_path = Path(input("Enter the name of the file including the message: "))
if source_path.exists():
break
print("Please input a valid path")
while True:
dest_path = Path(input("Enter the name of the file where the encrypted message will be written: "))
if dest_path.exists():
break
print("Please input a valid path")
You can use inbuilt OS module in Python. Here is the code until the path is a valid path.
Note: Keeping a check for MAXIMUM RETRIES will help the code to not stuck in an infinite loop for the user.
import os
def getPath():
MAXIMUM_RETRIES = 5
count = 0
file_path = ""
while True:
count += 1
file_path = input("Enter the path: ")
if os.path.exists(file_path):
break
if count >= MAXIMUM_RETRIES:
print("You have reached maximum number or re-tries. Exiting...")
exit(1)
print("Invalid Path. Try again.")
return file_path
I want to read the 3 next lines in a file but from a given point
If a user is in the phonebook I display the user and the 3 next lines -> code snippet
import re
phonebook_rule = re.compile(r'\'\D{3,6}\'\'\D{3,13}\'\'\d{10}\'')
def myFunction(phonebooke):
print(phonebooke)
if begin == 1:
firstname = input('enter a firstname:')
lastname = input('enter a lastname:')
phone = input('enter a number:')
imp = (f'\'{firstname}\'\'{lastname}\'\'{phone}\'')
if phonebook_rule.match(imp):
phbook = open('Phonebook','a')
phbook.write('Fristname: ' + firstname + '\n')
phbook.write('Lastname: ' + lastname + '\n')
phbook.write('Phone: ' + phone + '\n')
phbook.close()
else:
print('Not a good format')
elif begin == 2:
search = input('Search a user:')
cnt = 1
if search in phbook.read():
print('This user is in the phonebook')
while True:
print(phbook.readlines())
cnt += 1
if cnt == 3:
break
else:
print('No user found')
else:
print('nothing')
begin = int(input('Chose a number 1 to 4:'))
print(myFunction(begin))
Don't know how to do this , especially the part when I need to start from "search" input and then display the 3 other lines...
Edit:
That's the only things I get with readlines()
There's a user called Matt in my phonebook or maybe I did something wrong ?
It might help to reinitialize the file object. I suspect that this is will do what you're looking for.
search = input('Search a user:')
phbook.close()
phbook = open('Phonebook','r')
for line in phbook:
line = line.strip()
if search in line:
print('This user is in the phonebook')
print(line) # print the line where you found the string
for _ in range(2):
print(phbook.readline()) # print the next 2 lines
break
else:
print('No user found')
I am fairly new to python and I need to make a program to ask 10 questions, save the score into a file and allow someone to read the scores in from the file.
My problem: I need to check if the person who has done the quiz already has a record in the file, and if so, I need to add their score to the end of their record.
The records should look like this:
name,score,score,score,score,
etc so they can be split using commas.
I am also looking for the simplest answer, not the most efficient. Also, if you could comment the code, it would make it much easier. Here is my code so far:
import random
import math
import operator as op
import sys
import re
def test():
num1 = random.randint(1, 10)
num2 = random.randint(1, num1)
ops = {
'+': op.add,
'-': op.sub,
'*': op.mul,
}
keys = list(ops.keys())
rand_key = random.choice(keys)
operation = ops[rand_key]
correct_result = operation(num1, num2)
print ("What is {} {} {}?".format(num1, rand_key, num2))
while True:
try:
user_answer = int(input("Your answer: "))
except ValueError:
print("Only enter numbers!")
continue
else:
break
if user_answer != correct_result:
print ("Incorrect. The right answer is {}".format(correct_result))
return False
else:
print("Correct!")
return True
print("1. Are you a student?")
print("2. Are you a teacher?")
print("3. Exit")
while True:
try:
status = int(input("Please select an option:"))
except ValueError:
print("Please enter a number!")
else:
if status not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
if status == 1:
username=input("What is your name?")
while not re.match("^[A-Za-z ]*$", username) or username=="":
username=input(str("Please enter a valid name (it must not contain numbers or symbols)."))
print ("Hi {}! Wellcome to the Arithmetic quiz...".format(username))
while True:
try:
users_class = int(input("Which class are you in? (1,2 or 3)"))
except ValueError:
print("Please enter a number!")
else:
if users_class not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
correct_answers = 0
num_questions = 10
for i in range(num_questions):
if test():
correct_answers +=1
print("{}: You got {}/{} {} correct.".format(username, correct_answers, num_questions,
'question' if (correct_answers==1) else 'questions'))
if users_class == 1:
class1 = open("Class1.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class1.write(newRecord)
class1.close()
elif users_class == 2:
class2 = open("Class2.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class2.write(newRecord)
class2.close()
elif users_class == 3:
class3 = open("Class3.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class3.write(newRecord)
class3.close()
else:
print("Sorry, we can not save your data as the class you entered is not valid.")
EDIT:
Add this function before your "test" function:
def writeUserScore(file, name, score):
with open (file, "r") as myfile:
s = myfile.read()
rows = s.split("\n")
data = {}
for row in rows:
tmp = row.split(",")
if len(tmp) >= 2: data[tmp[0]] = tmp[1:]
if name not in data:
data[name] = []
data[name].append(str(score))
output = ""
for name in data:
output = output + name + "," + ",".join(data[name]) + "\n"
handle = open(file, "w+")
handle.write(output)
handle.close()
After that, where you have "if users_class == 1:" do this:
writeUserScore("Class1.txt", username, str(correct_answers))
Do the same for the other two else ifs.
Let me know what you think!
Try using a dictionary to hold the existing file data.
Read the file in a variable called "str" for example. And then do something like this:
rows = str.split("\n")
data1 = {}
for row in rows:
tmp = row.split(",")
data1[tmp[0]] = tmp[1:]
When you have a new score you should then do:
if username not in data1:
data1[username] = []
data1[username] = str(correct_answers)
And to save the data back to the file:
output = ""
for name in data1:
output = outupt + name + "," + ",".join(data1[name]) | "\n"
And save the contents of "output" to the file.
PS: If you are not bound by the file format you can use a JSON file. I can tell you more about this if you wish.
Hope that helps,
Alex
First, define these functions:
from collections import defaultdict
def read_scores(users_class):
"""
If the score file for users_class does not exist, return an empty
defaultdict(list). If the score file does exist, read it in and return
it as a defaultdict(list). The keys of the dict are the user names,
and the values are lists of ints (the scores for each user)
"""
assert 0 <= users_class <= 3
result = defaultdict(list)
try:
lines =open("Class%d.txt"%users_class,'r').readlines()
except IOError:
return result
for line in lines:
# this line requires python3
user, *scores = line.strip().split(',')
# if you need to use python2, replace the above line
# with these two lines:
# line = line.strip().split(',')
# user, scores = line[0], line[1:]
result[user] = [int(s) for s in scores]
return result
def write_scores(users_class, all_scores):
"""
Write user scores to the appropriate file.
users_class is the class number, all scores is a dict kind of dict
returned by read_scores.
"""
f = open("Class%d.txt"%users_class,'w')
for user, scores in all_scores.items():
f.write("%s,%s\n"%(user, ','.join([str(s) for s in scores])))
def update_user_score(users_class, user_name, new_score):
"""
Update the appropriate score file for users_class.
Append new_score to user_name's existing scores. If the user has
no scores, a new record is created for them.
"""
scores = read_scores(users_class)
scores[user_name].append(new_score)
write_scores(users_class, scores)
Now, in the last portion of your code (where you actually write the scores out) becomes much simpler. Here's an example of writing some scores:
update_user_score(1, 'phil', 7)
update_user_score(1, 'phil', 6)
update_user_score(1, 'alice', 6)
update_user_score(1, 'phil', 9)
there will be two lines in Class1.txt:
phil,7,6,9
alice,6
We read the whole file into a dict (actually a defaultdict(list)),
and overwrite that same file with an updated dict. By using defaultdict(list), we don't have to worry about distinguishing between updating and adding a record.
Note also that we don't need separate if/elif cases to read/write the files. "Scores%d.txt"%users_class gives us the name of the file.
I have the following code:
#gets the filename from the user
b= input("Please enter a file name to be opened: ")
a = (b+".txt")
#main data storage and other boolean options
data =[]
result1 =[]
on = True
#File reading in main body with try and except functionality.
try:
check = open(a, 'r')
line =check.readlines()
for items in line:
breakup= items.split()
number, salary, position, first, oname1, oname2, last = breakup
data.append(tuple([last, first + ' ' + oname1 + ' ' + oname2, number, position, salary]))
except IOError as e :
print("Failed to open", fileName)
#Employee creation function, takes the line and stores it in the correct position.
def employee_creation():
result = [((item[0] +", "+ item[1]).ljust(30), int(item[2]), item[3].ljust(15), int(item[4])) for item in data]
for items in result:
result1.append((items[0][0:30], format(items[1], "^5d"), items[2][0:15], "£"+format((items[3]),"<8d")))
return(result)
employee_creation()
print(result)
while on == True:
print("Please select what option you would like to use to search for employees:")
option = int(input("""
1 - Salary (X to X)
2 - Job Titlle
3 - Name, Payroll Number
:"""))
if option == 1:
start = input("What range would you like to start from: ")
end = input("What is the maximum range you would like :")
for items in result:
print(items[3])
if items[3]>start and items[3]<end:
print(items)
else:
print("No employees with this information can be found")
on= False
else:
on= False
However my def employee_creation() doesn't actually return result. I need it to make it a global variable so that I can use it to launch personal querys against the data.
Can anyone see why its not working?
No need to use the evil global variables. You forgot to store the result of your function to another variable.
def employee_creation():
result = [((item[0] +", "+ item[1]).ljust(30), int(item[2]), item[3].ljust(15), int(item[4])) for item in data]
for items in result:
result1.append((items[0][0:30], format(items[1], "^5d"), items[2][0:15], "£"+format((items[3]),"<8d")))
return result # no need for () here
result = employee_creation() # store the return value of your function
print(result)
fileName = raw_input("Enter the filename: ")
n = input("Enter the line you want to look: ")
f = open(fileName,'r')
numbers = []
for line in f:
sentenceInLine = line.split('\n')
for word in sentenceInLine:
if word != '':
numbers.append(word)
print numbers
print len(numbers)
print numbers[n-1]
if n == 0:
print "There is no 0 line"
break
i think you missed to split sentenceInLine like sentenceInLine.split(' ')
You are looping over each line, then you split lines based on '\n'. That \n is a line break character. That would confuse your logic right there.
So it is a bit confusing what you are trying to do but you should check n after the user has inputed a value for n. not at the end.
You may want to also catch the exception where file cannot be found I think this is what you need:
fileName = raw_input("Enter the filename: ")
n = input("Enter the line you want to look: ")
if n == 0:
print "There is no 0 line"
sys.exit();
try:
f = open(fileName,'r')
except IOError:
print "Could not find file"
sys.exit()