5

here is an example text file

the bird flew
the dog barked
the cat meowed

here is my code to find the line number of the phrase i want to delete

phrase = 'the dog barked'

with open(filename) as myFile:
    for num, line in enumerate(myFile, 1):
        if phrase in line:
            print 'found at line:', num

what can i add to this to be able to delete the line number (num) i have tried

lines = myFile.readlines()
del line[num]

but this doesnt work how should i approach this?

derpyherp
  • 455
  • 4
  • 9
  • 18
  • possible duplicate of [Deleting a specific line in a file (python)](http://stackoverflow.com/questions/4710067/deleting-a-specific-line-in-a-file-python) – TerryA Jul 19 '13 at 13:38

7 Answers7

8

You could use the fileinput module to update the file - note this will remove all lines containing the phrase:

import fileinput

for line in fileinput.input(filename, inplace=True):
    if phrase in line:
        continue
    print(line, end='')
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • 1
    If you already know the index of the line you want to remove in the variable `n`, you can change the condition to `if fileinput.lineno() == n:` – tripleee Jul 24 '14 at 06:14
  • Do you need `from __future__ import print_function` at the top? I get errors for trying the `end=''` . Even when doing the import I still get errors. Sorry python newb. – Nick Oct 11 '14 at 22:17
  • Ahh nvm `from __future__ import print_function` , must be the first import. odd – Nick Oct 11 '14 at 22:19
  • 1
    @Nick if you're using Python 2.x, then you can do the same using `print line,` (the trailing comma suppresses the default newline being appended - similar to, but not exactly the same as the `end=''` in 3.x's `print` function) – Jon Clements Oct 12 '14 at 16:07
  • I don't know how this got selected the answer, as it literally does nothing to the file itself. The question was to update the file in place, not print everything but a specific line... – MrDysprosium May 07 '21 at 15:22
3

A user by the name of gnibbler posted something similar to this on another thread.

Modify the file in place, offending line is replaced with spaces so the remainder of the file does not need to be shuffled around on disk. You can also "fix" the line in place if the fix is not longer than the line you are replacing

If the other program can be changed to output the fileoffset instead of the line number, you can assign the offset to p directly and do without the for loop

import os
from mmap import mmap

phrase = 'the dog barked'
filename = r'C:\Path\text.txt'

def removeLine(filename, num):
    f=os.open(filename, os.O_RDWR)
    m=mmap(f,0)
    p=0
    for i in range(num-1):
        p=m.find('\n',p)+1
    q=m.find('\n',p)
    m[p:q] = ' '*(q-p)
    os.close(f)

with open(filename) as myFile:
    for num, line in enumerate(myFile, 1):
        if phrase in line:            
            removeLine(filename, num)
            print 'Removed at line:', num
HKImpact
  • 610
  • 1
  • 9
  • 23
3

I found another solution that works efficiently and gets by without doing all the icky and not so elegant counting of lines within the file object:

del_line = 3    #line to be deleted: no. 3 (first line is no. 1)

with open("textfile.txt","r") as textobj:
    list = list(textobj)    #puts all lines in a list

del list[del_line - 1]    #delete regarding element

    #rewrite the textfile from list contents/elements:
with open("textfile.txt","w") as textobj:
    for n in list:
        textobj.write(n)

Detailed explanation for those who want it:

(1) Create a variable containing an integer value of the line-number you want to have deleted. Let's say I want to delete line #3:

del_line = 3

(2) Open the text file and put it into a file-object. Only reading-mode is necessary for now. Then, put its contents into a list:

with open("textfile.txt","r") as textobj:
    list = list(textobj)

(3) Now every line should be an indexed element in "list". You can proceed by deleting the element representing the line you want to have deleted:

del list[del_line - 1]

At this point, if you got the line no. that is supposed to be deleted from user-input, make sure to convert it to integer first since it will be in string format most likely(if you used "input()").

It's del_line - 1 because the list's element-index starts at 0. However, I assume you (or the user) start counting at "1" for line no. 1, in which case you need to deduct 1 to catch the correct element in the list.

(4) Open the list file again, this time in "write-mode", rewriting the complete file. After that, iterate over the updated list, rewriting every element of "list" into the file. You don't need to worry about new lines because at the moment you put the contents of the original file into a list (step 2), the \n escapes will also be copied into the list elements:

with open("textfile.txt","w") as textobj:
    for n in list:
        textobj.write(n)

This has done the job for me when I wanted the user to decide which line to delete in a certain text file. I think Martijn Pieters's answer does sth. similar, however his explanation is to little for me to be able to tell.

brendon-ai
  • 517
  • 3
  • 7
  • 20
Rob
  • 31
  • 1
2

Assuming num is the line number to remove:

import numpy as np
a=np.genfromtxt("yourfile.txt",dtype=None, delimiter="\n") 
with open('yourfile.txt','w') as f:    
    for el in np.delete(a,(num-1),axis=0):
        f.write(str(el)+'\n')
Lee
  • 29,398
  • 28
  • 117
  • 170
  • 2
    Weirdness points for using Numpy for this. Does it offer any real benefit (such as perhaps being faster in some scenarios)? – tripleee Jul 24 '14 at 06:46
  • 1
    never expected numpy answer for this case. Thanks it's new for me +1. – Pygirl Jan 15 '21 at 11:25
0

You start counting at one, but python indices are always zero-based.

Start your line count at zero:

for num, line in enumerate(myFile):  # default is to start at 0

or subtract one from num, deleting from lines (not line):

del lines[num - 1]

Note that in order for your .readlines() call to return any lines, you need to either re-open the file first, or seek to the start:

myFile.seek(0)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

Try

lines = myFile.readlines()  

mylines = [x for x in lines if x.find(phrase) < 0]  
aar cee
  • 239
  • 3
  • 10
0

Implementing @atomh33ls numpy approach So you want to delete any line in the file that contain the phrase string, right? instead of just deleting the phrase string

import numpy as np

phrase = 'the dog barked'

nums = [] 

with open("yourfile.txt") as myFile:
    for num1, line in enumerate(myFile, 0):
    # Changing from enumerate(myFile, 1) to enumerate(myFile, 0)
        if phrase in line:
            nums.append(num1)

a=np.genfromtxt("yourfile.txt",dtype=None, delimiter="\n", encoding=None ) 
      
with open('yourfile.txt','w') as f:
    for el in np.delete(a,nums,axis=0):
        f.write(str(el)+'\n')

where text file is,

the bird flew
the dog barked
the cat meowed

produces

the bird flew
the cat meowed
Subham
  • 397
  • 1
  • 6
  • 14