Chris Aung
Chris Aung

Reputation: 9492

Read/Write text file

I am trying to change a some lines in a text file without affecting the other lines. This is what's inside the text file called "text.txt"

this is  a test1|number1
this is a test2|number2
this is a test3|number2
this is a test4|number3
this is a test5|number3
this is a test6|number4
this is a test7|number5
this is a test8|number5
this is a test9|number5
this is a test10|number5

My objective is to change the line 4 and line 5 but keep the rest same.

mylist1=[]
for lines in open('test','r'):
    a=lines.split('|')
    b=a[1].strip()
    if b== 'number3':
        mylist1.append('{}|{} \n'.format('this is replacement','number7'))
    else:
         mylist1.append('{}|{} \n'.format(a[0],a[1].strip()))
myfile=open('test','w')
myfile.writelines(mylist1)

Even though the code works, I am wondering if there is any better and efficient way to do it? Is it possible to read the file just by line number?

Upvotes: 1

Views: 31450

Answers (5)

kampu
kampu

Reputation: 1421

It's not wholly clear whether your intent is to identify the lines to be replaced by their value, or by their line number.

If the former is your intent, you can get a list of lines like this:

with open('test','r') as f:
    oldlines = f.read().splitlines()

If there's a danger of trailing whitespace, you could also:

Then you can process them like this:

newlines = [ line if not line.strip().endswith('|number3') else 'this is replacement|number7' for line in oldlines]

Open the destination file (I'm assuming you want to overwrite the original, here), and write all the lines:

with open('test','w') as f:
    f.write("\n".join(newlines))

This is a general pattern that's useful for any kind of simple line-filtering.

If you meant to identify the lines by number, you could just alter the 'newlines' line:

 newlines = [ line if i not in (3, 4) else 'this is replacement|number7' for i, line in enumerate(oldlines)]

Upvotes: 0

Lev Levitsky
Lev Levitsky

Reputation: 65791

There is not much you can improve. But you have to write all lines to a new file, either changed or unchanged. Minor improvements would be:

  • using the with statement;
  • avoiding storing lines in a list;
  • writing lines without formatting in the else clause (if applicable).

Applying all of the above:

import shutil
with open('test') as old, open('newtest', 'w') as new:
    for line in old:
        if line.rsplit('|', 1)[-1].strip() == 'number3':
            new.write('this is replacement|number7\n')
        else:
            new.write(line)
shutil.move('newtest', 'test')

Upvotes: 11

oleg
oleg

Reputation: 4182

try this solution

with open('test', inplace=True) as text_file:
    for line in text_file:
         if line.rsplit('|', 1)[-1].strip() == 'number3':
             print '{}|{} \n'.format('this is replacement', 'number7')
         else:
             print line

Upvotes: 0

jamylak
jamylak

Reputation: 133554

import fileinput

for lines in fileinput.input('test', inplace=True):
    # inplace=True redirects stdout to a temp file which will
    # be renamed to the original when we reach the end of the file. this
    # is more efficient because it doesn't save the whole file into memeory
    a = lines.split('|')
    b = a[1].strip()
    if b == 'number3':
        print '{}|{} '.format('this is replacement', 'number7')
    else:
        print '{}|{} '.format(a[0], a[1].strip())

Upvotes: 3

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798676

No. Files are byte-oriented, not line-oriented, and changing the length of a line will not advance the following bytes.

Upvotes: 2

Related Questions