How to replace strings in a text file using Python? - python

I am a newbie in programming and I'm trying to create a small text-based game with a high score feature. The game is fine, but I have a problem in trying to replace the highscore in the file if the player gets a higher score when the game is finished.
I created a function to make the file if it doesn't exist by using:
def createhighscore():
hs = os.listdir()
highscore = None
if "highscore.txt" not in hs:
highscore = open("highscore.txt", 'w')
a = ["normal null 0\n", "expert null 0\n"]
highscore.writelines(a)
return highscore
So now the highscore.txt file has two lines:
normal null 0
expert null 0
normal/expert = the gamemode the player picked, i put the gamemode in the variable "mode"
null = replaced with player name, i put the player name in the variable "player"
0 = replaced with the new highscore, i put the score in the variable "score"
I tried creating a code that split each word in each line into a list by using split(), and then checking if there is a condition where the score the player gets is higher than the current score for either mode. My code:
checkline = open("highscore.txt", "r+")
for line in checkline:
x = line.split()
if x[0] == mode.lower() and int(x[2]) < score:
line.replace(x[1], player)
line.replace(x[2], str(score))
print("NEW HIGHSCORE")
checkline.close()
checkline = open("highscore.txt", "r+")
for line in checkline:
x = line.split()
if x[0] == mode.lower() and int(x[2]) < score:
x[1] = player
x[2] = score
print("NEW HIGHSCORE")
checkline.close()
So if a player with the name "Raka" gets a score of 20 in Expert mode, the highscore.txt file should change to:
normal null 0
expert Raka 20
Sadly my code doesn't do anything and the content of the highscore.txt stays the same. I tried tweaking my code and until now I still haven't found the solution. I think my code does detect if the player gets a new highscore since "NEW HIGHSCORE" gets printed, but the text doesn't get replaced. I hope you guys can help me. Also, sorry for my bad English since it's not my first language. Thanks!

I made a simple script to write the changes in the highscores.txt, even if there are no changes the text file is overwritten.
score = 30
mode = "normal"
player = "Raka"
f = open("highscore.txt", "r")
lines = f.read().split("\n")
#remove empty lines in the lines list
lines = [line for line in lines if line.strip() != ""]
for x in range(0, len(lines)):
words = lines[x].split(" ")
if words[0] == mode and score > int(words[2]):
lines[x] = mode +" "+player+" "+str(score)
#Write the changes in highscore.txt
outF = open("highscore.txt", "w")
for line in lines:
outF.write(line)
outF.write("\n")
outF.close()

Try using the following code:
check_high_score = open("highscore.txt", "r")
list_high_scores = check_high_score.readlines()
check_high_score.close()
to_write = []
for score in list_high_scores:
if mode.lower() == "normal":
if int(list_high_scores[0][2]) < score:
to_write.append("normal " + player + " " + str(score))
else:
to_write.append(list_high_scores[0])
elif mode.lower() == "expert":
if int(list_high_scores[1][2]) < score:
to_write.append("expert " + player + " " + str(score))
else:
to_write.append(list_high_scores[1])
write_score = open("highscore.txt", "w")
write_score.writelines(to_write)
write_score.close()
I'd recommend storing the data in a new variable after opening a file rather than directly accessing it, makes it easier to logic on it and improves the code readability. Also, try to use different variable names each time you make a file-handler. As to why your code is not working, I think it's because you haven't closed the file with checkline.close() after replacing the contents. Unless you close the file, the program will not push the data from the cache to the disk and the contents will remain the same. Alternatively, you can also use the flush (checkline.flush() in your case) method to push the data into the file but keep in mind, in doing so, the file handler will keep running in the background and take memory while the close function will terminate it. Memory may not be a problem now but can be important in larger projects and it's good practice.

Related

Comparing line in external file with a variable and and replacing it

I'm trying to create a scoreboard in an external file in python and having a bit of an issue.
score = 14
with open("score.txt") as f:
data_1 = f.read()
lines = data_1.split("\n")
line_1 = lines[0]
line_1 = int(line_1)
if line_1 < score:
score = str(score)
with open("score.txt", "w") as a:
a.write(score)
Every time I'd run the code, it would write 14 in the first line and then delete everything else in the file.
I want the code to check if score is bigger than the first line in the file and if it is, shift everything down a line and put score there instead and if it is smaller than the first line do the same with the others

Saving Highscore in textfile for a game

I created a small game. I would like to save the 3 highest scores in a textfile and display them after the game. I created a textfile with following content: 0 0 0 (should represent the status before you play game for first time). I created 2 functions update_highscores() and display_highscores(), but nothing happens after finishing the game. the achieved scores are not stored in the text file and the highscores were not displayed after the game. How can i save and show the highscores?
def update_highscores():
global score, scores
file = "C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
scores=[]
with open(filename, "r") as file:
line = file.readline()
high_scores = line.split()
for high_score in high_scores:
if (score > int(high_score)):
scores.append(str(score) + " ")
score = int(high_score)
else:
scores.append(str(high_score) + " ")
with open (filename, "w") as file:
for high_score in scores:
file.write(high_score)
def display_highscores():
screen.draw.text("HIGHSCORES", (350,150), fontsize=40, color = "black")
y = 200
position = 1
for high_score in scores:
screen.draw.text(str(position) + ". " + high_score, (350, y), color = "black")
y = y + 25
position = position + 1
The update_highscores code should work fine if you change
file = "C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
to
filename = r"C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
The two things that changed were: changing file to filename, otherwise this code throws an exception because filename is not defined. I assume it's meant to be this way. The second thing I changed is adding an r before the string so that the backslashes are interpreted literally. Two other options that would also work are:
"C:\\Programmieren\\Eigene Spiele\\Catch The Bananas\\highscores.txt"
or
"C:/Programmieren/Eigene Spiele/Catch The Bananas/highscores.txt"
Just remember that a single backslash in a non-raw string will usually try to escape the next character.
Aside from that, just make sure that the file exists, and that it contains 0 0 0, or any sequence of characters separated by spaces. If the file is not initialized properly, there won't be any scores to replace.
This code works for me, so if there's still a problem, it's just with displaying the scores. They update in the file just fine. But I don't know what library you're using for screen, so I can't test that.
Oh, also: make sure you're actually calling the function. I assume it's elsewhere in your code and you just omitted it. Obviously, your code won't work if you don't call the function.
Here is my code that works. Just replace the path to highscores.txt and run this code by itself. If it works, the problem is somewhere else in your code, and we won't be able to help you unless you give us more of your code.
score = int(input("Enter new score: "))
scores = []
def update_highscores():
global score, scores
filename = r"path\to\highscores.txt"
scores=[]
with open(filename, "r") as file:
line = file.readline()
high_scores = line.split()
for high_score in high_scores:
if (score > int(high_score)):
scores.append(str(score) + " ")
score = int(high_score)
else:
scores.append(str(high_score) + " ")
with open (filename, "w") as file:
for high_score in scores:
print(high_score)
file.write(high_score)
update_highscores()
input()

how to add a file contents to a variable in python 3.5

I'm not very experienced so please know I'm trying as hard as I can. How do I add the file's first contents (eg. 65) to a new entered number, then overwrite the file to save it?
Any advice is greatly appreciated.
Here is my programming:
henry = 0
emily = 0
george = 0
points = 0
file = open('nfc.txt','r+')
for line in file:
print(line)
if input("Who would you like to give points to? ") == "henry":
points = int(input("How many points would you like to give to Henry? "))
henry = henry + points
print("Henry now has",henry, "points")
points = 0
file.write(str(henry)+" ")
file.write(str(emily)+" ")
file.write(str(george)+" ")
file.close()
else:
print("That name is not valid")
Your code is working when 'nfc.txt' exists in the directory. If the file is not there then use 'w+'. Mind it, if the file already exists then it will overwrite the existing one. Here is the link for more information: https://www.tutorialspoint.com/python3/python_files_io.htm. Also, think about the comment made by ahed87.
I hope, it will help.
p.s: new edit to improve the answer
assuming I understood your question this should do it. it opens the file and gets the values before appending them with user input and writes them to the file. I have commented it in case you get lost I hope this helps.
file = open('nfc.txt', 'r+') ### opens file
f = file.read() ### reads file and assigns it to variable f
f = f.splitlines() ### slits file into list at any neline "\n"
scores = {} ### creates dictionary to store data
for line in f:
line = line.replace(':', '') ### replaces colons with nothing
line = line.split() ### splits name from score
scores[line[0]] = int(line[1]) ###appends dictionary so name is key and score is values
name = input("Who would you like to give points to?").lower() ### user input
if name in scores.keys(): ### checks to see if input is a dict key
point = int(input(
"How many points would you like to give to {}?".format(name))) ### formats name into next input question
scores[name] += point ### adds value to current score
scores['total'] += point ### adds value to change total
file.seek(0) ### sets position in file to start
file.truncate() ### deletes all data in current file
for key in list(scores.keys()): ### gets all keys from dict to ittereate
file.write("{}: {}\n".format(key, str(scores[key]))) ### writes info to file with \n for new person
file.close() ### closes file IMPORTANT
else:
print("That name is not valid")
I do hope you don't mind having to scroll for the comments I know it is not very pythonic
Now it works
You have to use 'w' to write in a file
henry = 0
emily = 0
george = 0
points = 0
file = open('nfc.txt', 'w+')
for line in file:
print(line)
if input("Who would you like to give points to? ") == "henry":
points = int(input("How many points would you like to give to Henry? "))
henry = henry + points
print("Henry now has", henry, "points")
points = 0
file.write(str(henry) + " ")
file.write(str(emily) + " ")
file.write(str(george) + " ")
file.close()
else:
print("That name is not valid")
and in the file you got this

How do I add a user inputted number into my text file list?

I am not able to add a number to my list that i have in a text file and don't know how to.
Code so far:
def add_player_points():
# Allows the user to add a points onto the players information.
L = open("players.txt","r+")
name = raw_input("\n\tPlease enter the name of the player whose points you wish to add: ")
for line in L:
s = line.strip()
string = s.split(",")
if name == string[0]:
opponent = raw_input("\n\t Enter the name of the opponent: ")
points = raw_input("\n\t Enter how many points you would like to add?: ")
new_points = string[7] + points
L.close()
This is a sample of a key in the text file. There are about 100 in the file:
Joe,Bloggs,J.bloggs#anemailaddress.com,01269 512355, 1, 0, 0, 0,
^
The value that i would like this number to be added to is the 0 besides the number already in there, indicated by an arrow below it. The text file is called players.txt as shown.
A full code answer would be helpful.
I didn't like what i wrote earlier, and the use case isn't optimal for fileinput. I took a similar piece of code from the sources and suited it for your needs.
Notice that for each line you modify, you are re-writing an entire file. I strongly suggest changing the way you handle data if performance is a concern.
This code works tho.
from tempfile import mkstemp
from shutil import move
from os import remove, close
def add_player_points():
file_path = "test.txt"
name = raw_input("\n\tPlease enter the name of the player whose points you wish to add: ")
#Create temp file
fh, abs_path = mkstemp()
with open(abs_path,'w') as new_file:
with open(file_path) as old_file:
for line in old_file:
stripped_line = line.strip()
split_string = stripped_line.split(",")
print name == split_string[0]
if name == split_string[0]:
opponent = raw_input("\n\t Enter the name of the opponent: ")
points = raw_input("\n\t Enter how many points you would like to add?: ")
temp = int(split_string[5]) + int(points) # fool proofing the code
split_string[5] = str(temp)
stripped_line = ','.join(split_string)# line you shove back into the file.
print stripped_line
new_file.write(stripped_line +'\n')
else:
new_file.write(line)
close(fh)
#Remove original file
remove(file_path)
#Move new file
move(abs_path, file_path)
Search and replace a line in a file in Python
Editing specific line in text file in python
You wouldn't expect it to be that big of an issue, but it is.
Another tip: might wanna check the module csv - it might be smarter for file editing than what i showed here.
2 issues, first you're never saving your changes to the file. You need to build the string and then save it at the end with L.write("your new string"). Second, you need to cast the points to ints before adding them, change
new_points = string[7] + points
to
new_points = int(string[7]) + int(points)
Edit: Fixed the syntax as mentioned in the comments

Deleting and inserting a score into a text file form python

I have created a text based game in python 3.3 were users pick a class for their character. I want the game to store three scores so an average can be taken. My problem is that i am unsure how to get the program to search for a name in the file and delete there oldest score, This is what the file where the scores are saved looks like:
Bennie
33
62
94
Josh
82
55
31
Jackie
10
4
3
My current code that sees if they have done the game before and if not writes there score to the file if they have i have got the code to split the lines and read them. It needs to delete the score closet to their name and insert and new score just before the next name but i am unsure how to do this. This is my current code
class_choice = input('Enter Class one, Class two or Class three.')
if class_choice == "One":
text_file = 'class1.txt'
elif class_choice == "Two":
text_file = 'class2.txt'
elif class_choice == "Three":
text_file = 'class3.txt'
else:
False
first_time = input('Is this the first you have completed this game: Yes or No?')
if first_time == 'Yes':
with open(text_file, "a") as file:
file.write("{}\n".format(name))
file.write("0\n")
file.write("0\n")
file.write("{}\n".format(score))
sys.exit()
else:
file = open(text_file, 'r')
lines = file.read().splitlines()
giving a sample python method to add a score to the file (pseudo-code) modify as needed to suit your needs (your requirement is not the most efficient method):
def add_score(user, score, text_file):
lines = text_file.splitlines()
count = len(lines)
user_exists = False
user_index = -1
num_scores = 3
user_num_scores = 0
for i in range(count-1):
line = lines[i]
if user == line:
# user previous scores start after here
user_exists = True
user_index = i
break
if not user_exists:
# user does not exist, create by appending
lines.append(user)
lines.append(str(score))
else: # user exists, fix the scores
j=1
while j <= num_scores:
line = lines[user_index+j]
j += 1
if line.isdigit():
# user score line
user_num_scores +=1
if user_num_scores == num_scores:
for i in range(1,num_scores-1): lines[user_index+i] = lines[user_index+i+1] # shift up
lines[user_index+num_scores] = str(score) # add the latest score
else: # just append/insert the score, as the previous scores are less than num_scores
lines.insert(user_index+user_num_scores, str(score))
return "\n".join(lines) # return the new text_file back
use like this:
text = file.read()
updated_text = add_score('UserName', 32, text)
Note the function given will not change the file it will just operate on the given file contents (as text_file argument). This is on purpose since if the function itself manipulated the files it would limit its use, since one can read or write the file in any convenient instant for the whole application. So this function only operates on strings. This is not the most efficient method, for example one can use a file per user and a much simpler format, but since this what is asked for this answer covers only that.
When you have finished adding scores and manipulating the files, you can update the file by writing the updated_text back to it. (Probably if the file is already opened in read mode, you will have to close it and re-open it in write mode).
To write (update) the file with the new contents use sth like this:
file.write(updated_text)
for example see here for python file I/O operations
It is not possible to change a single line inside a file. You can only append content at the end of the file or override the entire content.
If you wat to store the scores on a file, you need to read the file line by line storing each line in an auxiliar variable (concatenating lines) and when you reach the line you need to modify, concatenate the modified line into the auxiliar variable. Then keep reading the file line by line and storing it into the auxiliar variable.
When done, write down the content of the auxiliar variable in the file.
Why dont you try creating an .ini file and store your data in the attributes under sections. It's framework suits your requirements. It kind-of works like an xml file, but since your input and output parameters are limited (as you mentioned; 3 scores), it seems like the best option to opt for. Simply go through ini file manipulation using python in python docs and you will know what to do. Cheers !
My problem is that i am unsure how to get the program to search for a name in the file and delete there oldest score
I would create several .txt (or .dat) files with the name "< class >_stats[.txt]" (without the spaces, obviously). From there:
class_choice = raw_input("Choose your class")
# if needing stats
f = open("%s_stats.txt" % class_choice, "r+")
lines = f.readlines()
f.close()
stats = [float(i) for i in lines] # i.e. [3, 5.5, 4]
# rest of game
# overwrite with new stats
new_stat = get_new_stat()
f = open("%s_stats.txt" % class_choice, "w")
f.write("\n".join([str(i) for i in stats]))
However, I would recommend just keeping the stats, you may want them later, and text is cheap. Instead of reading all lines, simply open the file for appending, read the last three, and append the new stat to the end when you get your new stat, i.e.
f = open("%s_stats.txt")
lines = f.readlines[-3:] # reads last 3
f.close()
# stuff
f = open("%s_stats.txt", "a")
f.write(get_new_stat())
f.close()

Categories