Text file:
1. line
2. line
3. line
4. line
...
code:
quit = False
while not quit:
with open("sample.txt", "r+") as file:
n = len(file.read().split("\n"))
idea = input(f"Enter idea no. {n}: ")
if idea == "--q":
quit = True
elif idea == "--list":
with open("sample.txt", "r") as file:
print(f"\n{file.read()}\n")
elif idea == f"--del {type(int)}": #if user enter i.e. '--del 4' it dels line 4
with open("sample.txt", "r") as file:
l = idea.split(" ")[1]
lines = file.readlines()
del lines[l]
del_idea = open("sample.txt", "w")
for line in lines:
del_idea.write(line)
del_idea.close()
else:
file.write(f"{n}. {idea}\n")
How to implement delete a line selected by user?
problematic line: elif idea == f"--del {type(int)}"
User wants to delete chosen line using syntax i.e --del 4, command must be in one single line. If a digit is not given after blank " " (space) in input, should loop until enters it properly.
Any ideas? Should use regex ?
Your problem is that f-strings don't work like regex. type(int) is the actual type class so you're basically checking if the user literally input "--del <class 'type'>" (which is never the case I believe).
You can use regex to match a pattern of del followed by a number (i.e, r"--del \d+"), but an easier way would be to split the input and access the arg and number easily:
quit = False
while not quit:
with open("sample.txt", "r+") as file:
n = len(file.read().split("\n"))
idea = input(f"Enter idea no. {n}: ").split()
if idea[0] == "--q":
quit = True
elif idea[0] == "--list":
...
elif idea[0] == "--del":
with open("sample.txt", "r") as file:
l = idea[1]
...
else:
file.write(f"{n}. {idea}\n")
Related
I used this code to delete a word from a text file.
f = open('./test.txt','r')
a = ['word1','word2','word3']
lst = []
for line in f:
for word in a:
if word in line:
line = line.replace(word,'')
lst.append(line)
f.close()
f = open('./test.txt','w')
for line in lst:
f.write(line)
f.close()
But for some reason if the words have the same characters, all those characters get deleted. So for e.g
in my code:
def cancel():
global refID
f1=open("refID.txt","r")
line=f1.readline()
flag = 0
while flag==0:
refID=input("Enter the reference ID or type 'q' to quit: ")
for i in line.split(','):
if refID == i:
flag=1
if flag ==1:
print("reference ID found")
cancelsub()
elif (len(refID))<1:
print("Reference ID not found, please re-enter your reference ID\n")
cancel()
elif refID=="q":
flag=1
else:
print("reference ID not found\n")
menu()
def cancelsub():
global refIDarr, index
refIDarr=[]
index=0
f = open('flightbooking.csv')
csv_f = csv.reader(f)
for row in csv_f:
refIDarr.append(row[1])
for i in range (len(refIDarr)):
if refID==refIDarr[i]:
index=i
print(index)
while True:
proceed=input("You are about to cancel your flight booking, are you sure you would like to proceed? y/n?: ")
while proceed>"y" or proceed<"n" or (proceed>"n" and proceed<"y") :
proceed=input("Invalid entry. \nPlease enter y or n: ")
if proceed=="y":
Continue()
break
elif proceed=="n":
main_menu
break
exit
break
def Continue():
lines = list()
with open('flightbooking.csv', 'r') as readFile:
reader = csv.reader(readFile)
for row in reader:
lines.append(row)
for field in row:
if field ==refID:
lines.remove(row)
break
with open('flightbooking.csv', 'w') as writeFile:
writer = csv.writer(writeFile)
writer.writerows(lines)
f = open('refID.txt','r')
a=refIDarr[index]
print(a)
lst = []
for line in f:
for word in a:
if word in line:
line = line.replace(word,'')
lst.append(line)
print(lst)
f.close()
f = open('refID.txt','w')
for line in lst:
f.write(line)
f.close()
print("Booking successfully cancelled")
menu()
When the code is run, the refID variable has one word stored in it, and it should replace just that word with a blank space, but it takes that word for e.g 'AB123', finds all other words which might have an 'A' or a 'B' or the numbers, and replace all of them. How do I make it so it only deletes the word?
Text file before running code:
AD123,AB123
Expected Output in the text file:
AD123,
Output in text file:
D,
Edit: I have added the entire code, and maybe you can help now after seeing that the array is being appended to and then being used to delete from a text file.
here's my opinion.
refIDarr = ["AB123"]
a = refIDarr[0] => a = "AB123"
strings in python are iterable, so when you do for word in a, you're getting 5 loops where each word is actually a letter.
Something like the following is being executed.
if "A" in line:
line = line.replace("A","")
if "B" in line:
line = line.replace("B","")
if "1" in line:
line = line.replace("1","")
if "2" in line:
line = line.replace("2","")
if "3" in line:
line = line.replace("3","")
they correct way to do this is loop over refIDarr
for word in refIDarr:
line = line.replace(word,'')
NOTE: You don't need the if statement, since if the word is not in the line it will return the same line as it was.
"abc".replace("bananan", "") => "abc"
Here's a working example:
refIDarr = ["hello", "world", "lol"]
with open('mytext.txt', "r") as f:
data = f.readlines()
for word in refIDarr:
data = [line.replace(word, "") for line in data]
with open("mytext.txt", "w") as newf:
newf.writelines(data)
The problem is here:
a=refIDarr[index]
If refIDarr is a list of words, accessing specific index makes a be a word. Later, when you iterate over a (for word in a:), word becomes a letter and not a word as you expect, which causes eventually replacing characters of word instead the word itself in your file.
To avoid that, remove a=refIDarr[index] and change your loop to be:
for line in f:
for word in refIDarr:
if word in line:
line = line.replace(word,'')
I am having trouble with matching variables to lines in txt, and removing the lines.
I am currently doing a hotel room booking program in which I am having trouble removing a booking from my text file.
This is how my lines in my text file are formatted:
first_name1, phonenumber1 and email 1 are linked to entry boxes
jeff;jeff#gmail.com;123123123;2019-06-09;2019-06-10;Single Room
def edit_details(self,controller):
f = open("Bookings.txt")
lines = f.readlines()
f.close()
x = -1
for i in lines:
x += 1
data = lines[x]
first_name1 = str(controller.editName.get())
phonenumber1 = str(controller.editPhone.get())
email1 = str(controller.editEmail.get())
checkfirst_name, checkemail, checkphone_num, checkclock_in_date, checkclock_out_date, checkroom = map(str, data.split(";"))
if checkfirst_name.upper() == first_name1.upper() and checkemail.upper() == email1.upper() and checkphone_num == phonenumber1:
controller.roomName.set(checkfirst_name)
controller.roomEmail.set(checkemail)
controller.roomPhone.set(checkphone_num)
controller.roomCheckin.set(checkclock_in_date)
controller.roomCheckout.set(checkclock_out_date)
controller.roomSelect.set(checkroom)
print(controller.roomName.get())
print(controller.roomSelect.get())
controller.show_frame("cancelBooking")
break
elif x > len(lines) - int(2):
messagebox.showerror("Error", "Please Enter Valid Details")
break
I have the user to enter their details to give me the variables but I don't know how to match these variables to the line in the text file to remove the booking.
Do I have to format these variables to match the line?
This is what i have tried but it deletes the last line in my file
line_to_match = ';'.join([controller.roomName.get(),controller.roomEmail.get(),controller.roomPhone.get()])
print(line_to_match)
with open("Bookings.txt", "r+") as f:
line = f.readlines()
f.seek(0)
for i in line:
if i.startswith(line_to_match):
f.write(i)
f.truncate()
I have kind of added a pseudocode here. You can join the variables using ; and validate if the line startswith those details, like below.
first_name1, phonenumber1, email1 = 'jeff', 'jeff#gmail.com', '123123123'
line_to_match = ';'.join([first_name1, email1, phonenumber1])
for i in line:
...
if i.startswith(line_to_match):
# Add your removal code here
...
I am having trouble reading strings and numbers from a file with a while loop. There are imaginary names with their age and number of siblings in a text file. I want to read the names, the age, and the number of siblings in the text file with a while loop. If you need more information to solve the problem let me know. Help is very appreciated
outfile = open('practice.txt', 'w')
def main():
print('this program will print the name and age of a person')
details()
def details():
choice = input('Would you like to enter your name, age, and number of siblings? Enter Y for yes and N for no: ')
while choice != 'N' and choice != 'n':
name = input('Enter your name: ')
age = input('Enter your age: ')
siblings = input('Enter the number of siblings: ')
outfile.write(name + '\n')
outfile.write(str(age + '\n'))
outfile.write(str(siblings + '\n'))
choice = input('Would you like to continue? Enter Y for yes and N for no: ')
outfile.close()
main()
This code above is the code that allows me to get the information and store it in a text file. The code below is that im working on so i can read from the file.
infile = open('practice.txt', 'r')
line = infile.readline()
while line != '':
line = infile.readline()
age = int(line)
infile.close()
This is what my data file looks like. BELOW
joe
56
2
john
27
5
james
14
3
You're writing each value on a line, then when you read it you're only reading one line. Read each line back as you write them
with open('practice.txt', 'r') as infile:
while True:
name = infile.readline()
if not name:
break
age = int(infile.readline())
siblings = int(infile.readline())
It's ALMOST right, but a few details:
Open infile not as readline(), but just as "", otherwise, it will skip the first line.
Don't test choice for "N" and for "n", just do something like if choice.lower() == "n":.
Also read the siblings, or do something to skip them, otherwise it will confuse the code, as "2" will be read as the line, "john" will be read as the age, but int("john") will spit an error
Since each person takes 3 lines in the file, you need to read 3 lines each time through the loop.
You should also use rstrip() to remove the newlines at the end of each line.
line = infile.readline()
while line:
name = line.rstrip()
line = infile.readline()
age = int(line.rstrip())
line = infile.readline()
siblings = int(line.rstrip())
# ...
# do something with `name`, `age`, and `siblings`
# ...
line = infile.readline()
Here is this block of code I'm trying to finish:
elif parameter == 'statistics':
outfile.write(stats(infile))
for line in infile:
outfile.write(line)
So essentially, I am trying to write the statistics of the file into the new file that is being copied. The statistics works and everything as when I open the file, the statistics are written in. However, I noticed because of the two outfile.write it seems to close after the first one, so only the statistics go in and not the rest of the content in the original file.
The error that I am getting is this:
ValueError: I/O operation on closed file.
I am unsure why the file is closing.
EDIT: Here is the whole code, as requested
def copy_file():
infile_name = input("Please enter the name of the file to copy: ")
infile = open(infile_name, 'r', encoding='utf8')
parameter = input("Please enter a parameter(line numbers, Gutenberg trim, statistics, none): ")
outfile_name = input("Please enter the name of the new copy: ")
outfile = open(outfile_name, 'w', encoding='utf8')
counter = 1
if parameter == 'line numbers':
for line in infile:
outfile.write(f' {counter:6}: {line}')
counter += 1
elif parameter == 'Gutenberg trim':
copyStart = False
for line in infile:
#print(line.strip())
if '*** START' in line.strip():
copyStart = True
continue
elif '*** END' in line.strip():
copyStart = False
break
if copyStart == True:
outfile.write(line)
elif parameter == 'statistics':
outfile.write(stats(infile))
for line in infile:
outfile.write(line)
else:
for line in infile:
outfile.write(line)
infile.close()
outfile.close()
copy_file()
EDIT2: So sorry for not including it. Here is the stats function:
def stats(text) -> str:
with text as infile:
totallines = 0
emplines = 0
characters = 0
for line in infile:
totallines += 1
characters += len(line)
if len(line.strip()) == 0:
emplines += 1
lines = totallines - emplines
totalaveChars = characters/totallines
nonempaveChars = characters/lines
result = (f'{totallines:5} lines in list \n'
f'{emplines:5} empty lines in list \n'
f'{totalaveChars:5.1f} average characters per line \n'
f'{nonempaveChars:5.1f} average chars per non-empty line')
return result
print(stats(open('ASH.txt', 'r', encoding='utf8')))
Here is the result from stats:
13052 lines in list
2666 empty lines in list
44.6 average characters per line
56.0 average chars per non-empty line
The issue is in the stats function. The with statement will close the file with the local name text, which is infile in your case!
def stats(text) -> str:
totallines = 0
emplines = 0
characters = 0
for line in text:
totallines += 1
characters += len(line)
if len(line.strip()) == 0:
emplines += 1
lines = totallines - emplines
totalaveChars = characters/totallines
nonempaveChars = characters/lines
result = (f'{totallines:5} lines in list \n'
f'{emplines:5} empty lines in list \n'
f'{totalaveChars:5.1f} average characters per line \n'
f'{nonempaveChars:5.1f} average chars per non-empty line')
return result
In your main program, you passed to the function stats the variable infile, which is a file. You do not need to reopen it with with inside the stats functions. Moreover, with will ensure the closing at the end. Thus in your main loop, the infile is closed after the call on stats.
Try the following;
def copy_file():
infile_name = input("Please enter the name of the file to copy: ")
parameter = input("Please enter a parameter(line numbers, Gutenberg trim, statistics, none): ")
outfile_name = input("Please enter the name of the new copy: ")
counter = 1
with open(infile_name, 'r', encoding='utf8') as infile:
with open(outfile_name, 'w', encoding='utf8') as outfile:
if parameter == 'line numbers':
for line in infile:
outfile.write(f' {counter:6}: {line}')
counter += 1
elif parameter == 'Gutenberg trim':
copyStart = False
for line in infile:
#print(line.strip())
if '*** START' in line.strip():
copyStart = True
continue
elif '*** END' in line.strip():
copyStart = False
break
if copyStart == True:
outfile.write(line)
elif parameter == 'statistics':
outfile.write(stats(infile))
for line in infile:
outfile.write(line)
else:
for line in infile:
outfile.write(line)
copy_file()
Using with open(filename, 'r') as file: it will automatically close the file once the operation has finished, and not before.
elif parameter == 'statistics':
outfile.write(stats(infile))
for line in infile:
outfile.write(line)
... only the statistics go in and not the rest of the content in the
original file ...
My educated guess is that the stats function consumes and possibly
closes the input stream (IS).
If stats is somehow well behaved and limits itself to consuming the
IS, one can rewind it
...
infile.seek(0) # rewind the input stream
for line in infile:
outfile.write(line)
If, on the other hand, stats is a bit disruptive and closes
altogether the IS one can use the .name attribute of the file object
to reopen it, like this
...
for line in open(infile.name):
outfile.write(line)
This second solution works even in the first, milder hypotesis and
works even if the code was passed the infile file object from a
outer call.
Another possibility, if you can access and modify the stats source
code, is to undo the reading performed by the function, memorizing
the current position in the input stream before any read operation
and later rewind the IS to that position
def stats(infile):
...
current_pos = infile.tell()
# do your stuff
...
infile.seek(current_pos)
return workload
For this to work, of course, the file object has not to be closed
before the .seek(), either explicitly (by a .close()) or
implicitly (by falling outside the scope of a with block).
If this is your situation (closed file), please remove either the
explicit infile.close() or the (unnecessary) with statement and
the rewind will be correct.
This program is supposed to replace the letters ö,ä,õ,ü with different letters. After completing one row it produces an empty row and I don't know why. I have tried to understand it for some time, but I couldn't really understand why it doesn't give me desired output.
f = input("Enter file name: ")
file = open(f, encoding="UTF-8")
for sentence in file:
sentence = sentence.upper()
for letter in sentence:
if letter == "Ä":
lause = sentence.replace(letter, "AE")
elif letter == "Ö" or täht == "Õ":
lause = sentence.replace(letter, "OE")
elif letter == "Ü":
lause = sentence.replace(letter, "UE")
print(sentence)
Reading each line in includes the trailing newline. Your print() also includes a newline so you will get an empty row. Try print(sentence, end='') as follows:
filename = input("Enter file name: ")
with open(filename, encoding="UTF-8") as f_input:
for sentence in f_input:
sentence = sentence.upper()
for letter in sentence:
if letter == "Ä":
lause = sentence.replace(letter, "AE")
elif letter == "Ö" or täht == "Õ":
lause = sentence.replace(letter, "OE")
elif letter == "Ü":
lause = sentence.replace(letter, "UE")
print(sentence, end='')
Note: using with open(... will also automatically close your file afterwards.
You might also want to consider the following approach:
# -*- coding: utf-8
filename = input("Enter file name: ")
replacements = [('Ä', 'AE'), ('ä', 'ae'), ('Ö', 'OE'), ('ö', 'oe'), ('Õ', 'OE'), ('õ', 'oe'), ('Ü', 'UE'), ('ü', 'ue')]
with open(filename, encoding='utf-8') as f_input:
text = f_input.read()
for from_text, to_text in replacements:
text = text.replace(from_text, to_text)
print(text)
This does each replacement on the whole text rather than line by line. It also preserves the case.
I won't fix your program, just try to answer why it doesn't do what you are expecting:
The program doesn't run: in line 14 the variable "täht" might be a typo, supposed to be "letter"
You store the result of replace() in variable "lause" but never use it
by default print() adds "\n" at the end, but you can override it (see help(print) in the python shell)