How do I delete multiple lines in a text file with python? - python

I am practicing my python skills by writing a Phone book program. I am able to search and add entries but I am having a lot of trouble deleting entries.
I am trying to find a line that matches my search and delete it as well as the next 4 lines. I have a function to delete here:
def delete():
del_name = raw_input("What is the first name of the person you would like to delete? ")
with open("phonebook.txt", "r+") as f:
deletelines = f.readlines()
for i, line in enumerate(deletelines):
if del_name in line:
for l in deletelines[i+1:i+4]:
f.write(l)
This does not work.
How would I delete multiple entries from a text file like this?

Answering your direct question: you can use fileinput to easily alter a text file in-place:
import fileinput
file = fileinput.input('phonebook.txt', inplace=True)
for line in file:
if word_to_find in line:
for _ in range(4): # skip this line and next 4 lines
next(file, None)
else:
print line,
In order to avoid reading the entire file into memory, this handles some things in the background for you - it moves your original file to a tempfile, writes the new file, and then deletes the tempfile.
Probably better answer: it looks like you have rolled a homemade serialization solution. Consider using a built-in library like csv, json, shelve, or even sqlite3 to persist your data in an easier-to-work-with format.

Related

How can I search for someones name then replace the number in that same line as the persons name?

I have the following data in a file called data.txt and would like to be able to add to the numbers at the end and replace them in the file without creating a new one:
Alfreda,art,2015,35
brook,biology,2015,3
charlie,chemistry,2015,140
dolly,Design,2015,120
Emilia,English,2015,150
Fiona,french,2015,40
Grace,Greek,2015,12
Hanna,history,2015,15
Here is the code I currently have:
with open("data.txt", "r") as f:
newline=[]
for word in f.line():
newline.append(word.replace(35,str(New))
with open("data.txt", "w") as f:
for line in newline :
f.writelines(line)
If you just want to add string to each line then update the file, this code can solve your problem but this is not optimal.
with open("data.txt", "r") as myFile:
newline=[]
# Use the readlines method to get all the lines
for line in myFile.readlines():
# Remove the \n character with the rstrip method
line = line.rstrip('\n')
newline.append(line+",35\n") # Don't forget to add \n
# Test
print newline
myFile.close()
with open("data.txt", "w") as myFile:
for line in newline :
myFile.writelines(line)
If this is not your problem, try to use the pickle module and work with objects, it will be easier.
I'm going to have to make some of your question up. If you have a file and you want to update it, the updates have to come from somewhere. The code in the question has a New variable but there is no indication of how New is supposed to get a value, or how the program is supposed to know which row to update.
I'm going to assume you have a file of updates called updates.txt that looks like this (and it is deliberately not in alphabetical order):
Emilia,45
Alfreda,35
So after your program runs the resulting file will have two rows different:
Alfreda,art,2015,70 ...this one
brook,biology,2015,3
charlie,chemistry,2015,140
dolly,Design,2015,120
Emilia,English,2015,195 ...and this one
Fiona,french,2015,40
Grace,Greek,2015,12
Hanna,history,2015,15
But the rest the same.
Since your sample data file is a .csv file I am using the Python csv module, rather than picking the data apart by hand. It doesn't matter much with simple data like this but it's a good module to know about.
import csv
marks = {}
# Read in existing data into a dictionary:
# key is name, value is a list [subject, year, score]
# like this: {"Alfreda": ["art",2015,35], ... }
# This is to make it easy to do random updates based on name
with open("data.txt", "r") as f:
for row in csv.reader(f):
name,subject,year,score = row
marks[name] = [subject,int(year),int(score)]
# Read in updates and apply each line to the corresponding entry in marks
with open("updates.txt", "r") as f:
for row in csv.reader(f):
name,added_score = row
try:
marks[name][2] += int(added_score) # for example marks["Alfreda"][2] += int("35")
except KeyError:
print(f"Name {name} not found to update, nothing done")
# Write out updated dictionary:
with open("data.txt", "w") as f:
writer = csv.writer(f,lineterminator="\n")
for name in sorted(marks.keys(), key=lambda n: n.lower()):
row=[name]+marks[name] # for example ["Alfreda"] + ["art",2015,70]
writer.writerow(row)
This line:
for name in sorted(marks.keys(), key=lambda n: n.lower()):
looks complicated but it is needed because you obviously expect the names Alfreda brook charlie dolly Emilia Fiona Grace Hanna to be in that order. But just doing the obvious
for name in sorted(marks.keys()):
will put them in the order Alfreda Emilia Fiona Grace Hanna brook charlie dolly.
In the interests of keeping the code simple and as close to your original as possible, it does no validity checks, so if this line
charlie,chemistry,2015,140
was wrongly entered as
charlie,chemistry,2015,14O
(with the letter O instead of a zero), the program will just fail. Ditto if the update file is missing a comma somewhere.
This works and will do what I think you want. But...
There are issues with the design. Your program reads in the data from data.txt, then overwrites it with new data. But suppose your program fails just after this line:
with open("data.txt", "w") as f:
Then you won't have your original data (because the call to open() truncated it), and you won't have the new data either (because you haven't written it out yet). Or suppose you accidentally run the program twice. There will be no way to tell you have done that.
You can provide some insurance against this sort of mishap by using the fileinput module, like this:
import fileinput
# Read in existing data
with fileinput.input("data.txt", inplace=True, backup=".bkp") as f:
for row in csv.reader(f):
name,subject,year,score = row
marks[name] = [subject,int(year),int(score)]
With this change, your updates will be in data.txt as before, but your original data will still be around, in a file called data.txt.bkp.
But that is just a fix. It avoids the real issue, which is that you really have a database application and you are trying to implement it using textfiles. The code above is all very well for an exercise, but it's not robust and it won't scale.

RegEx Python Find and Print to a new document

Sorry if this is a dumb lump of questions, but I had a couple things I was hoping to inquire about. Basically, what I am trying to do is take a file that is being sent where a bunch of data is getting clumped all together that is supposed to be on separate lines, sort through it, and print each statement on its own line. The thing I don't know is how to create a new document for everything to be dumped into, nor do I know how to print into that document where each thing is on its new line.
I've decided to try and tackle this task while using Regular Expressions and Python. I want my code to look for any of four specific strings (MTH|, SCN|, ENG|, or HST|) and copy everything after it UNTIL it runs into one of those four strings again. At that point I need it to stop, record everything it copied, and then start copying the new string. I need to make it read past new lines and ignore them, which I hope to accomplish with
re.DOTALL
Basically, I want my code to take something like this:
MTH|stuffstuffstuffSCN|stuffstuffstuffENG|stuffstuffstuffHST|stuffstu
ffstuffSCN|stuffstuffstuffENG|stuffstuffstuffHST|stuffstuffstuffMTH|s
tuffstuffstuffSCN|stuffstuffstuffENG|stuffstuffstuff
And turn into something nice and readable like this:
MTH|stuffstuffstuff
SCN|stuffstuffstuff
ENG|stuffstuffstuff
HST|stuffstuffstuff
SCN|stuffstuffstuff
ENG|stuffstuffstuff
HST|stuffstuffstuff
MTH|stuffstuffstuff
SCN|stuffstuffstuff
ENG|stuffstuffstuff
While also creating a new document and pasting it all in that .txt file. My code looks like this so far:
import re
re.DOTALL
from __future__ import print_function
NDoc = raw_input("Enter name of to-be-made document")
log = open("C:\Users\XYZ\Desktop\Python\NDoc.txt", "w")
#Need help with this^ How do I make new file instead of opening a file?
nl = list()
file = raw_input("Enter a file to be sorted")
xfile = open(file)
for line in xfile:
l=line.strip()
n=re.findall('^([MTH|SCN|ENG|HST][|].)$[MTH|SCN|ENG|HST][|]',l)
#Edited out some x's here that I left in, sorry
if len(n) > 0:
nl.append(n)
for item in nl:
print(item, file = log)
In the starting file, stuffstuffstuff can be number, letters, and various symbols (including | ), but no where except where they are supposed to be will MTH| SCN| ENG| HST| occur, so I want to look specifically for those 4 strings as my starts and ends.
Aside from being able to create a new document and paste into it on separate lines for each item in list, will the above code accomplish what I am trying to do? Can I scan .txt files and excel files? I don't have a file to test it on till Friday but I am supposed to have it mostly done by then.
Oh, also, to do things like:
import.re
re.DOTALL
from __future__ import print_function
do I have to set anything external? Are these addons or things I need to import or are these all just built into python?
This regex will take your string and put newlines in between each string you wanted to separate:
re.sub("(\B)(?=((MTH|SCN|ENG|HST)[|]))","\n\n",line)
Here is the code I was testing with:
from __future__ import print_function
import re
#NDoc = raw_input("Enter name of to-be-made document")
#log = open("C:\Users\XYZ\Desktop\Python\NDoc.txt", "w")
#Need help with this^ How do I make new file instead of opening a file?
#nl = list()
#file = raw_input("Enter a file to be sorted")
xfile = open("file2")
for line in xfile:
l=line.strip()
n=re.sub("(\B)(?=((MTH|SCN|ENG|HST)[|]))","\n\n",line)
#Edited out some x's here that I left in, sorry
if len(n) > 0:
nl=n.split("\n")
for item in nl:
print(item)
I've tested this version with input data that has no newlines. I also have a version that works with newlines. If this doesn't work, let me know and I'll post that version.
The main environmental changes I made are that I'm reading from a file named "file2" in the same directory as the python script and I'm just writing the output to the screen.
This version assumes that there are newlines in your data and just reads the whole file in:
from __future__ import print_function
import re
#NDoc = raw_input("Enter name of to-be-made document")
#log = open("C:\Users\XYZ\Desktop\Python\NDoc.txt", "w")
#Need help with this^ How do I make new file instead of opening a file?
#nl = list()
#file = raw_input("Enter a file to be sorted")
xfile = open("file")
line = xfile.read()
l=line.strip()
l=re.sub("\n","",l)
n=re.sub("(\B)(?=((MTH|SCN|ENG|HST)[|]))","\n\n",l)
print(n)

Remove line from a text file after read

I have a text file named 1.txt which contains the following:
123456
011111
02222
03333
and I have created a python code which copy the first line to x number of folders to file number.txt
then copy the second to x number of folders:
progs = int(raw_input( "Folders Number : "))
with open('1.txt', 'r') as f:
progs2 = f.read().splitlines()
progs3 = int(raw_input( "Copy time for each line : "))
for i in xrange(progs):
splis = int(math.ceil(float(progs)/len(progs3)))
with open("{0}/number.txt".format(pathname),'w') as fi:
fi.write(progs2[i/splis])
I want to edit the code to remove the line after copying it to the specified number of folder;
like when the code copy the number 123456 I want it to be deleted from the file so when I use the program again to continue from the second number.
Any idea about the code?
I'd like to write this as a comment but I do not have the necessary points
to do that so I'll just write an answer. Adding up on Darren Ringer's answer.
After reading the line you could close the file and open it again overwriting
it with the old content except for the the line which you want to remove,
which has already been described in this answer:
Deleting a specific line in a file (python)
Another option would be to use in-place Filtering using the same filename
for your output which would replace your old file with the filtered content. This
is essentially the same. You just don't have to open and close the file again.
This has also already been answered by 1_CR in the following question and can also
be found at https://docs.python.org/ (Optional in-place filtering section):
Deleting a line from a text file
Adapted to your case it would look something like this:
import fileinput
import sys, os
os.chdir('/Path/to/your/file')
for line_number, line in enumerate(fileinput.input('1.txt', inplace=1)):
if line_number == 0:
# do something with the line
else:
sys.stdout.write(line) # Write the remaining lines back to your file
Cheers
You could load all the lines into a list with readlines(), then when you get a line to work with simply remove it from the list and then write the list to the file. You will be overwriting the entire file every time you perform a read (not just removing the data inline) but there is no way to do it otherwise while simultaneously ensuring the file contents are up-to-date (Of which I am aware).

Reading text from a text file in python

I am having trouble trying to figure out how to import text from a text file easily or at least a memorable method. I am trying to make a program that insults the user (for school), that brings in a word/s from one text file, adds another word/s from the second file and the final word/s from the third text file...
I am having trouble finding a way of coding to do this...I have the random number up and running to pick the text I just need to know how to access strings or text in a text file.
The easiest way is to use the with statement. It takes care of closing the file for you.
with open("file.txt") as f:
for line in f:
# do something with line
Or read the data into directly into a list:
with open("file.txt") as f:
lines = list(f)
# do something with lines

How do I modify the last line of a file?

The last line of my file is:
29-dez,40,
How can I modify that line so that it reads:
29-Dez,40,90,100,50
Note: I don't want to write a new line. I want to take the same line and put new values after 29-Dez,40,
I'm new at python. I'm having a lot of trouble manipulating files and for me every example I look at seems difficult.
Unless the file is huge, you'll probably find it easier to read the entire file into a data structure (which might just be a list of lines), and then modify the data structure in memory, and finally write it back to the file.
On the other hand maybe your file is really huge - multiple GBs at least. In which case: the last line is probably terminated with a new line character, if you seek to that position you can overwrite it with the new text at the end of the last line.
So perhaps:
f = open("foo.file", "wb")
f.seek(-len(os.linesep), os.SEEK_END)
f.write("new text at end of last line" + os.linesep)
f.close()
(Modulo line endings on different platforms)
To expand on what Doug said, in order to read the file contents into a data structure you can use the readlines() method of the file object.
The below code sample reads the file into a list of "lines", edits the last line, then writes it back out to the file:
#!/usr/bin/python
MYFILE="file.txt"
# read the file into a list of lines
lines = open(MYFILE, 'r').readlines()
# now edit the last line of the list of lines
new_last_line = (lines[-1].rstrip() + ",90,100,50")
lines[-1] = new_last_line
# now write the modified list back out to the file
open(MYFILE, 'w').writelines(lines)
If the file is very large then this approach will not work well, because this reads all the file lines into memory each time and writes them back out to the file, which is very inefficient. For a small file however this will work fine.
Don't work with files directly, make a data structure that fits your needs in form of a class and make read from/write to file methods.
I recently wrote a script to do something very similar to this. It would traverse a project, find all module dependencies and add any missing import statements. I won't clutter this post up with the entire script, but I'll show how I went about modifying my files.
import os
from mmap import mmap
def insert_import(filename, text):
if len(text) < 1:
return
f = open(filename, 'r+')
m = mmap(f.fileno(), os.path.getsize(filename))
origSize = m.size()
m.resize(origSize + len(text))
pos = 0
while True:
l = m.readline()
if l.startswith(('import', 'from')):
continue
else:
pos = m.tell() - len(l)
break
m[pos+len(text):] = m[pos:origSize]
m[pos:pos+len(text)] = text
m.close()
f.close()
Summary: This snippet takes a filename and a blob of text to insert. It finds the last import statement already present, and sticks the text in at that location.
The part I suggest paying most attention to is the use of mmap. It lets you work with files in the same manner you may work with a string. Very handy.

Categories