very new to Python and having a weird issue which I can't find a solution for online.
I need to take a binary file containing data and display it in a table format, which is almost working except that it pushes the end of the first line to the next and throwing everything off as shown below.
Table print issue
Code for the function to view the binary file data as below.
As its for an assignment I don't think I can use 3rd party table modules like tabulate so this was my attempt at just doing it with string formatting. It was moving the end of the each line to the next when printing with an entire empty line so I added the end=' ' bit to the print statement but still no dice. There's probably an easier way of displaying the data as a table anyway but I'd be happy with it if I could just figure out why it won't stay on one line when printing the data under the headers :|
def functionRetrieve():
while True:
filename = input("Please enter a binary file name:")
try:
open(filename + ".bin", 'r')
except FileNotFoundError:
print("Wrong file name or file type")
else:
break
filename = filename + ".bin"
print("\033[4m|{:^24}|{:^24}|{:^14}|{:^14}|{:^14}|{:^14}|\033[0m".format("Last Name", "First Name", "Games Played", "Total Points", "Average", "Position"))
with open(filename, 'rb') as textfile:
for line in textfile:
line = line.decode('utf-8')
data = list(line.split(","))
lastname = data[0]
firstname = data[1]
gamesplayed = data[2]
totalpoints = data[3]
average = data[4]
position = data[5]
print("|{:^24}|{:^24}|{:^14}|{:^14}|{:^14}|{:^14}|".format(lastname, firstname, gamesplayed, totalpoints, average, position), end='')
with end='' you're overwriting the default end value of print from newline '\n' to ''. So basically you're printing one loooong line instaed of multiple lines. Thats why each new print seems to be with one additional space indent. The lines are appending instead of printing below eachother.
In your header row you do not do this, that is why the first row looks "normal". This should fix it:
print("|{:^24}|{:^24}|{:^14}|{:^14}|{:^14}|{:^14}|".format(lastname, firstname, gamesplayed, totalpoints, average, position))
Related
I currently have a working phonebook with 4 options. The only thing is, the search option is not printing all of the matches.
If I type a name and there is a match in the phonebook it will print that line into a text file (phone.txt02, which is blank).
Then after all of the matches have been printed to the text file, my program reads the new text file and returns them in my preferred format.
The readFile function isn't working properly right now for the new text file.
It works fine on phone.txt (the original text file) which contains the same information... Names and numbers separated by a comma.
Because this works, I cannot figure out why the readFile function will not work for phone02.txt when the values are also name,number \n
def readFile1(filename):
phonebook = []
file = open(filename, "r")
for aline in file:
person = aline.split(",")
if person[1][-1] == '\n' :
pn = person.pop(1)
person.append(pn[:-1])
phonebook.append(person)
elif person[1][-1] != '\n' :
phonebook.append(person)
file.close()
return phonebook
def printEntries1(phonebook):
readFile1("phone02.txt")
print("Name Phone Number")
print("------------------- --------------")
for i in range (len(phonebook)):
person = phonebook[i]
print(i,"{:<20s} {:>14s}".format(person[0],person[1]))
print("------------------- --------------")
def searchEntry():
search = input("Type a name to search for")
with open("phone.txt", "r") as file:
lines = file.readlines()
for line in lines:
if search in line:
outfile = open("phone02.txt", "a")
outfile.write(line)
phonebook = readFile1("phone02.txt")
print(readFile1("phone02.txt"))
printEntries1(phonebook)
outfile = open("phone02.txt", "r+")
outfile.truncate()
print(searchEntry())
I am not sure how to have the printEntries print all of the matches (name and number) from phone02.txt
Here is an example of the phone.txt file
Polly,549-5393
Bud Wieser,(213) 477-3928
Jack,277-4829
Mike Dunleavy,335-3453
Robert Darn,219-473-4373
Earl Lee,703-304-8393
Tim Bean,(612) 493-2629
Bud,(701) 487-8522
If I were to input "Bud" it would print the 2 lines that contain bud to phone02.txt but not print them correctly.
It seems that (in this example) when the 2 lines containing Bud are put into phone02.txt, only the first line is printing
Name. Number
------------------- ------------------
0 Bud Wieser. (218) 477-3928
I know this is a lot of information for most likely an easy fix, but I think it should help with the issue.
Thanks for any help.
You never closed the writer to phone02.txt. All new lines will be saved in the file only after you close the file writer or directly tell python to do save the changes to the file. Please try
if search in line:
outfile = open("phone02.txt", "a")
outfile.write(line)
outfile.close()
Anyway, you open the file for reading many times -- please either do it once before the loop and close afterwards, or open and close the writer for each iteration.
I am trying to convert from string to float. I am pulling the text from a file. Any help or hints would be greatly accepted. I am a newbie on coding. Thanks in advance.
def main():
name =["","","","","",""]
lname = ["","","","","",""]
grade = [0,0,0,0,0]
#total = 0
#count = len(name)
#average = total / count
# for i in range(len(grade)):
# total += grade[i]
#Intro
print("Grades Processing App!\n")
infile = open("gradestest.txt", "r")
for n in range(5):
line = infile.readline()
#split data into 3 fields
name[n], lname[n], grade[n] = line.split(",")
grade[n] = float(grade[n])
#infile.close()
#Display data on screen
print("Name\t\t\tGrade")
print("--------------------")
for i in range(5):
print(name[i], "\t", lname[i], "\t", grade[i])
print('\n')
infile.close()
#for n in range(len(grade)):
#total += grade[n]
# count +1
# print(average)
print('Enter the following student information')
FirstName = input("\tFirst name: ")
LastName = input("\tLast name: ")
Grade = float(input("\tTest grade : "))
infile = open("gradestest.txt", "a")
infile.write(name + "," + lname + "," + float(grade) + "\n")
infile.close()
main()
The problem in your code you can't write float values to file. You can only write string value, you can convert it to float when reading the file.
def main():
print("Grades Processing App!\n")
with open('test.txt') as fp:
data = [line.strip().split(",") for line in fp]
#Display data on screen
print("Name\t\t\tGrade")
print("--------------------")
for name, lname, grade in data:
print(name, "\t", lname, "\t", grade)
grades_avg = sum([float(val[2]) for val in data])/len(data)
print("\nAverage:", grades_avg)
print('\nEnter the following student information')
fname = input("\tFirst name: ")
lname = input("\tLast name: ")
grade = input("\tTest grade : ")
with open("test.txt", "a") as fp:
fp.write(fname + "," + lname + "," + grade + "\n")
main()
Hmmm...so there is quite a bit to discuss I think.
1) First, we note that in python you don't need to allocate memory for your objects. Hence, declaring the size and content of your variables is unnecessary. Python is dynamic, hence one would simply say, "x=[]", to begin a list. and then "x.append(7)" to append a 7 to a list. If you are using ipython (highly recommended) then you can play around with variables on-the-fly and see what they do. For example x.(press tab) will show you all the "methods" available for lists.
2) There are many functions in python that simplify doing repeated tasks. For example, the join method for strings, inserts any string between the sequence of strings your provide. Another example is that open() automatically closes files if the variable isn't used anymore, hence in python you can normally open, read, and close a file in one line.
3) Python highly revolves around iterators that allow you to simplify many many tasks. These include builtins, like sorted, reversed, map, filter, range, etc. It is highly recommended to become familiar with those, as they will greatly enhance your code.
Lets simplify your code a bit:
# Read all lines at once. No need to say 'r', that is the default.
# The file closes automatically when the variable falls out of scope.
lines = open('gradestest.txt').readlines()
# Split each line. You can do it all at once in a list comprehension.
lines = [line.split(',') for line in lines]
# Leaves all the entries alone but the last one. Python can access backwards.
# The line[:-1] means to access everything but the last item as a list.
# The line[-1] means to access the last item (which is grade).
lines = [line[:-1]+[float(line[-1])] for line in lines]
# There are other ways to read your file as well (probably faster).
# Python has a huge library of modules, like the csv module which is for
# opening and reading csv files.
# The join method inserts strings between other strings. The map function
# takes each item in an object and applies the given function to them. Hence,
# map(str,line) turned all the items into a string (including the item you
# made a float earlier.
print("Grades Processing App!\n")
print("Name\t\t\tGrade")
print("--------------------")
print('\n'.join('\t'.join(map(str,line)) for line in lines))
# Not quite sure what this code was for. You don't use your variables
# anywhere. Also you run float(grade) which I think will error, since
# grade is a list. Anyway, I think you meant to append to the file
# some new inputs.
print('Enter the following student information')
FirstName = input("\tFirst name: ")
LastName = input("\tLast name: ")
Grade = float(input("\tTest grade: "))
open('gradestest.txt','a').write(','.join([FirstName,LastName,Grade])+'\n')
Don't think I answered the original question. If you want to find an average in python, there are two builtin commands len() and sum() which count the number of items in a list and add up the items in a list. For example,
grades = [1,2,3,4,5]
average = sum(grades)/len(grades)
I know this is a lot more than you asked for, but since I left some long tips in the comments, I pasted them here with examples.
A tip about files: you can use with open('myfile.txt', 'r') as infile: and put the code that uses the file in that block under it. Once the execution of code leaves that block, the file is reliably closed - even in the case of an exception being thrown.
To address the question in your post, converting text to a float or int value is pretty simple. The only trouble is when the string data isn't in a format that can be converted to an int or float. The exception handling below will make your program a bit more robust and it won't blow up when the conversion fails. But looking at what you had in your code should work.
with open('gradestest.txt', 'r') as infile:
for line_no, line in enumerate(infile):
try:
name, lname, grade = line.split(',')
grade = float(grade)
except ValueError as ve:
print(f"Warning, file format incorrect on line "
f"{line_no + 1}: {ve}")
I added some fault tolerance to the loop that reads in grades. When .split() doesn't produce the right number of items, or float() fails trying to convert a non-numeric string, a ValueError is raised. The except block catches the ValueError and prints a warning about the file format, but the loop can continue to try and process the rest of the file.
Rather than have lists of data that rely on the index to associate different data with the same student, create a Student class that has data members for name and grade. That way you can iterate over the student list rather than iterating over a range of indices.
class Student:
def __init__(self, name, lname, grade=None):
self.name = name
self.lname = lname
self.grade = grade
The above isn't what some may consider a proper implementation of a class because we'll be accessing the data members directly from other code in your program. Since this is a very simple program that's just processing file data, and we only have three pieces of data to manage, we'll flex the coding standards a bit.
Now you have a way to reference grade and student data by attribute name on the student objects. And to be able to grab the list of students at different points in the program, we'll add them to a list.
student_list = []
with open('gradestest.txt', 'r') as infile:
for line_no, line in enumerate(infile):
try:
name, lname, grade = line.split(',')
grade = float(grade)
student_list.append( Student(name, lname, grade) )
except ValueError as ve:
print(f"Warning, file format incorrect on line "
f"{line_no + 1}: {ve}")
Then later in the program when we want to list out the students and their grades:
print(f"{'name':<20} Grade") # Pads 'name' to 20 characters with spaces.
for st in student_list:
print(f"{st.name+' '+st.lname:<20} {st.grade}")
I'm using f-strings to format the text. The text between curly braces is interpreted as Python code and returns strings at the positions in the string where they're at. The :<20 left-aligns and pads the text with spaces.
One last suggestion. This might be a little advanced, suppose you're maintaining student records and want to be able to save the information to a file, then come back to your program later and load your student objects back up with all their information in them, you could use the pickle module for that (although you might also consider a simple database - the sqlite module is pretty good)
Pandas is also a good option if you're working with tabulated student data - it can save its dataframes to file and retrieve them pretty easily.
Anyway, here's pickle:
import pickle
...
# Somewhere in your code...
save_file_y_n = input("Do you want to save student data? ")
if save_file_y_n.lower() in ['y', 'yes']:
file_name = input("Name of file: ")
# Write the Students out to a file.
pickle.dump(student_list, open(file_name, 'wb+'))
...
# Somewhere else in your code - or another script/program..
if load_file_y_n.lower() in ['y', 'yes']:
file_name = input("File name for student records: ")
# Reconstructs the Student objects from the file data
# with their name, lname, grades and any other attributes
# you may have added:
student_list = pickle.load(open(file_name, 'rb'))
print("List of students:")
for st in student_list:
print(f"st.name")
It's always a great idea to back your data up regularly in case the student data file gets somehow corrupted or accidentally deleted. You could even implement some code in your program to save student data in a new file each day and load the latest when the program starts.
A little information on this in case you're curious and not overwhelmed already https://wiki.python.org/moin/UsingPickle
Another option for saving application information is the json module. It can write basic data objects out to a file using plain text. https://docs.python.org/3/library/json.html
And of course you could use CSV (comma separated values) - there's a csv module for that, https://docs.python.org/3/library/csv.html?highlight=csv#module-csv.
I have tried to get help on this question all day, but none of the already-asked questions have solved my problem, and any answers I have asked to help me solve this problem have resulted in answers that didn't answer the question.
As it stands now, my program takes the values of MPG ratings represented in a CSV and puts them in a list. These lists represent maximum and minimum MPGs. Once the max/min MPG rating is found is where I get into my problem. I need to be able to print all the cars that have the minimum/maximum MPG value. Ideally, the models should be printed indented under the print statements for the maximum/minimum mileage ratings.
The way the CSV file is done the MPG ratings are in column 9 (index[8]). The make and models are in columns 2 and 3, respectively (index[1] and index[2], respectively). As you'll see in the code, I tried looping through the list and using an if statement to pull the make/model, but when I do that it does not work. I don't know if the files play a part or not, but any help would be appreciated.
# prints welcome screen, asks user what year they want vehicle data for, and asks user for file name to save vehicle data to
print("Welcome to EPA Mileage Calculator")
yearChoice = int(input("What year would you like to view data for? (2008 or 2009): "))
while yearChoice != 2008 and yearChoice != 2009:
print("Invalid input, please try again")
yearChoice = int(input("What year would you like to view data for? (2008 or 2009): "))
saveResults = input("Enter the filename to save results to: ")
def carData():
if yearChoice == 2008:
fileName = "epaVehicleData2008.csv"
elif yearChoice == 2009:
fileName = "epaVehicleData2009.csv"
fileIn = open(fileName, "r")
fileIn.readline()
minMPG = []
maxMPG = []
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[0] not in ['VANS - PASSENGER TYPE', 'VANS - CARGO TYPE', 'TRUCK', 'MINIVAN - 4WD', 'MINIVAN - 2WD']:
minMPG.append(int(dataList[8]))
maxMPG.append(int(dataList[8]))
maximumMPG = max(maxMPG)
minimumMPG = min(minMPG)
fileOut = open(saveResults, "w")
print("EPA City MPG Calculator", "(" + str(yearChoice) + ")", file=fileOut)
print("---------------------------------", file=fileOut)
print("Maximum Mileage (city):", maximumMPG, file=fileOut)
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[8] == maximumMPG:
print("\t", dataList[1], dataList[2], file=fileOut)
print("Minimum Mileage (city):", minimumMPG, file=fileOut)
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[8] == minimumMPG:
print("\t", dataList[1], dataList[2], file=fileOut)
fileIn.close()
fileOut.close()
def complete():
print()
print("Operation Success! Mileage data has been saved to", saveResults)
print("Thanks, and have a great day!")
def main():
carData()
complete()
main()
You open the input file only once via:
fileIn = open(fileName, "r")
But then you attempt to iterate over the lines in the file three times using that same file handle. You have three of these:
for line in fileIn:
Since you never close and reopen the file, and you don't do anything to seek back to the beginning of the file, the second and third such iterations will never do anything, because you've already reached the end of the file. Using this construct does not cause the file pointer to be rewound and the contents of the file to be iterated over another time.
Since your interesting print statements are in the second and third iterations over the file, which won't produce any new lines (the code in those iteration blocks will never be called), of course your print statements are never called and no output is generated.
To fix your problem, if this is the only thing wrong with your code, just put this line before each of the second and third iterations over the file:
f.seek(0)
to seek back to the beginning of the file and iterate over the contents a second and third time.
To be more efficient, you could read each line once and store it in a list. Then you could iterate over the list each time, and not have to read from the file three times. You could even do the strip and the split just once, making the code even more efficient.
Another small logic error that I see is that you skip one line in your first iteration over the file. I assume that this is to skip a header row at the start of the file. But you don't do this for the second and third iterations, so it seems that if you only add the seek() as I suggested, you'll be trying to process the header line as a data line. This would also be solved by reading the file once into a list. You'd skip the first line of the file while you do this. If you want to leave the code alone other than adding the seek(), you should also skip the first line before the second and third iterations.
I am trying to print a specific line from the file "Scores", which is option B. This is my code:
print("Option A: Show all scores\nOption B: Show a record\nOption Q: Quit")
decision = input("Enter A, B, C or Q: ")
myFile = open("Scores.txt", "rt")
if decision == "A":
record = myFile.read()
print(record)
myFile.close()
elif decision == "B" or decision == "b":
playerName = input("Enter a player name to view their scores: ")
record = myFile.read()
answer = record.find(playerName)
for line in answer:
print(line)
elif decision == "Q" or decision == "q":
exit
I went for Option B, then I entered a player name that holds the score of the player, but it throws this error message:
line 12, in <module>
for line in answer():
TypeError: 'int' object is not callable
A few cents from my side :
file = open("file")
lines = file.readlines()
for line in lines:
if playername in line:
print line
file.close()
Hope it works!
find() method returns a positive index if it succeeds, -1 otherwise
You should loop on your content line by line, as follows:
for line in myFile:
if line.find(playerName):
print(line)
A safer way to read the file and find data, so that you will not have OutOfMemory issues when storing the whole file in memory.
playerName = input("Enter a player name to view their scores: ")
with open("Scores.txt", 'r') as f:
for row in f:
if playerName in row:
print row
This way you will be using with that will close the file by itself either when the program ends or Garbage Collection kicks in. This way python will read the file line by line and store only 1 line in memory. So you can use huge files and do not worry about memory issues.
Hope it helps :)
Working with str methods will take more acrobatics. Try the following,
import re
p = re.compile(r"\b{}\b".format(playername)) # keep it ready
# inside option B
for line in myfile: # no need to `.read()` it
match = p.search(line)
if match:
print(line)
break # if there is only one record for playername
See if it works for you.
similar thing here:
Reading specific lines only (Python)
fp = open("file")
for i, line in enumerate(fp):
if line == playername:
print line
fp.close()
I also notice you don't close your file for each decision, should make that happen.
Few python idioms and small optimization
Here are many answer, my sample brings in few python idioms and optimize it a bit:
fname = "Scores.txt"
player_name = "Quido"
with open(fname) as f:
for line in f:
if player_name in line:
print line
break
print "Going on doing following tasks."
The with block will close the open file on exiting the inner block. No need to f.close(), safe
in case of problems to read the file.
for line in f: shows, that iterating over file open in text mode we get one line per iteration.
break after we print the line with the player will effectively stop iterating over lines assuming,
there is only one such line or that we are happy with the very first one. If this is not the case,
removing the break allows printing all lines containing the player name.
As lines returned from text file iterator contain new line, you may prefer to get rid of them. Use
print line.strip() in such case what will remove all blank characters from start and end of the line.
Final print is proving, the program continues after it processes all the lines.
It may happen, that you get no output for name, which appears to be present in the file. In such a
case, you might need to clarify letter case. For example, if your text file contains all the names
in exact casing, you have to enter the name properly.
Other option is to lower-case the player_name and compare it against lower cased line:
fname = "Scores.txt"
player_name = "Quido"
normalized_player_name = player_name.lower()
with open(fname) as f:
for line in f:
if normalized_player_name in line.lower():
print line.strip()
break # comment out to print all lines with the player
print "Going on doing following tasks."
Note, that we normalize the player_name outside from the loop to be a bit faster. Lower-casing inside the
loop would work, but would do the same task repeatedly.
The line is printed using exact letter cases as in the file.
I have written some code to compare two files via a search string.
The file = master data file
The checkfile = list of states & regions
When I have more than 1 state in the file that is not in sorted order it bombs out.
How can i get this to work without having to sort my "file"
The Error message: Traceback (most recent call last):
File "./gangnamstyle.py", line 27, in
csvLineList_2 = csv2[lineCount].split(",")
IndexError: list index out of range
My code:
#!/usr/bin/python
import csv
file = raw_input("Please enter the file name to search: ") #File name
checkfile = raw_input("Please enter the file with the search data: ") #datafile
save_file = raw_input("Please enter the file name to save: ") #Save Name
search_string = raw_input("Please type string to search for: ") #search string
#row = raw_input("Please enter column text is in: ") #column number - starts at 0
#ID_INDEX = row
#ID_INDEX = int(ID_INDEX)
f = open(file)
f1 = open(save_file, 'a')
csv1 = open(file, "r").readlines()
csv2 = open(checkfile, "r").readlines()
#what looks for the string in the file
copyline=False
for line in f.readlines():
if search_string in line:
copyline=True
if copyline:
f1.write(line)
for lineCount in range( len( csv1) ):
csvLineList_1 = csv1[lineCount].split(",")
csvLineList_2 = csv2[lineCount].split(",")
if search_string == csvLineList_2[0]:
f1.write(csvLineList_2[2])
f1.close() #close saved file
f.close() #close source file
#csv1.close()
#csv2.close()
OK, so that error message is an IndexError: list index out of range in the line csvLineList_2 = csv2[lineCount].split(","). There's only one indexing happening there, so apparently lineCount is too big for csv2.
lineCount is one of the values of range(len(csv1)). That makes it automatically in range for csv1. Apparently csv1 and csv2 are not the same length, causing the IndexError.
Now that's quite possible, because they contain lines from different files. Apparently the files don't have equal number of lines.
To be honest I have no clue why you are reading the lines into csv1 at all. You loop over those lines and split them (into the variable csvLineList_1), but you never use that variable.
I think your loop should just be:
for line in csv2:
parts = line.strip().split(",") # line.strip() removes whitespace and the newline
# at the end of the line
if search_string == parts[0]:
f1.write(parts[2] + "\n") # Add a newline, you probably want it
I hope this helps.
The error you're getting is probably due to the file lengths not being equal.
It's not exactly clear from what you've written, what you're hoping to do. It looks to me like (maybe) you want to find a search term in "master file", and if you find it, write the line you find to the "save file". It also looks to me like you want to find that same search term in the very first field of the "check file", and if you find it, write the contents of the third field into the "save file". If that's wrong, it's because your code has bugs.
Either way, there's a bunch of issues in the code you've posted, and you're probably going to get at least some mileage out of using the csv module to do what you're trying to do.
Maybe post a fuller problem description.
Edit:
import csv
import sys
def build_state_lookup(fn):
with open(fn) as infile:
reader = csv.reader(infile)
# throw away first line
reader.next()
# now build a dictionary mapping state to region
lookup = {state: region for (state, _, region) in reader}
return lookup
def process_big_file(in_fn, checkfile, out_fn):
lookup = build_state_lookup()
with open(in_fn) as infile:
with open(out_fn, 'w') as outfile:
reader = csv.reader(infile)
writer = csv.writer(outfile)
# output the header row
writer.writerow(reader.next() + ['Region'])
for row in reader:
state = row[0]
region = lookup.get(state, "No Region Found")
row.append(region)
writer.writerow(row)
def main():
process_big_file(*sys.argv[1:])
if __name__ == '__main__':
main()