6

I have a file as the format:

xxxxx
yyyyy
zzzzz
ttttt

And I need to write in file between xxxxx and yyyyy lines as:

xxxxx
my_line
yyyyyy
zzzzz
ttttt 
Piper
  • 1,266
  • 3
  • 15
  • 26
barp
  • 6,489
  • 9
  • 30
  • 37
  • 2
    [**Search and replace a line in a file in Python**](http://stackoverflow.com/questions/39086/search-and-replace-a-line-in-a-file-in-python) – Grijesh Chauhan Jan 15 '13 at 14:54
  • [**how to replace (update) text in a file line by line**](http://stackoverflow.com/questions/4778697/how-to-replace-update-text-in-a-file-line-by-line) – Grijesh Chauhan Jan 15 '13 at 14:55
  • 1
    What have you tried so far? If you have tried anything i'd suggest starting by reading about opening [files](http://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files) – oathead Jan 15 '13 at 14:55
  • @GrijeshChauhan -- This isn't exactly replacing, it's inserting which is *slightly* different. – mgilson Jan 15 '13 at 14:55
  • @mgilson I feel it would be helpful...because OP posted his question as requirement but didn't explained where he getting problem..that is the reason I commented link instead answer. – Grijesh Chauhan Jan 15 '13 at 14:59

2 Answers2

4
with open('input') as fin, open('output','w') as fout:
    for line in fin:
        fout.write(line)
        if line == 'xxxxx\n':
           next_line = next(fin)
           if next_line == 'yyyyy\n':
              fout.write('my_line\n')
           fout.write(next_line)

This will insert your line between every occurrence of xxxxx\n and yyyyy\n in the file.

An alternate approach would be to write a function to yield lines until it sees an xxxxx\nyyyyy\n

 def getlines(fobj,line1,line2):
     for line in iter(fobj.readline,''):  #This is necessary to get `fobj.tell` to work
         yield line
         if line == line1:
             pos = fobj.tell()
             next_line = next(fobj):
             fobj.seek(pos)
             if next_line == line2:
                 return

Then you can use this passed directly to writelines:

with open('input') as fin, open('output','w') as fout:
    fout.writelines(getlines(fin,'xxxxx\n','yyyyy\n'))
    fout.write('my_line\n')
    fout.writelines(fin)
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • @mgilson I not good at Python. I have C background. If question would be asked in `C` either I open file in `w+` or fist `r` then `w` How do you do with just `w` in Python? – Grijesh Chauhan Jan 15 '13 at 15:04
  • @GrijeshChauhan `'w'` in python means create a new file or if already exists then truncate it. – Ashwini Chaudhary Jan 15 '13 at 15:06
  • @GrijeshChauhan -- `open(filename,'w')` opens for just writing. with my moderate experience in C, the file modes are pretty similar. – mgilson Jan 15 '13 at 15:06
  • @mgilson ok you are doing read from `input` writing to `output` ..understood – Grijesh Chauhan Jan 15 '13 at 15:09
  • 2
    @GrijeshChauhan -- Yeah, when working with ASCII, it's reasonably difficult to do these things in place unless you want to read the entire file into memory ... but even then, it's not *really* in place. You just read the whole thing into memory and write it back out with the same filename... – mgilson Jan 15 '13 at 15:10
  • You can't mix `.tell()` and using the file as an iterator, sorry. Python uses a (largish) read-ahead buffer and `.tell()` will not give you the current position in the file but rather the position of the next buffer read. See [file.tell() inconsistency](http://stackoverflow.com/questions/14145082/14145118#14145118) – Martijn Pieters Jan 15 '13 at 15:37
  • @MartijnPieters -- Yeah. I just deleted that portion of the answer. Bummer. – mgilson Jan 15 '13 at 15:39
  • @mgilson: Use `for line in iter(fin.readline, ''):` instead and `.tell()` will be correct again. :-) – Martijn Pieters Jan 15 '13 at 15:41
  • @MartijnPieters -- Yeah, but that's ugly ... Perhaps an `itertools.takewhile` plus a python 3.3's `yield from` would be nicer ... `yield from it.takewhile(lambda x: x == 'xxxxx\n' or x == '',fobj)` and then just `yield line1`, repeate if the next line isn't equal to `line2` ... – mgilson Jan 15 '13 at 15:46
  • @MartijnPieters -- because it was supposed to be `if line == line1` ... Perhaps I should have tested this before posting ... :-X -- (I really just wanted to write a somewhat more clean version) – mgilson Jan 15 '13 at 15:47
  • @mgilson: I started solving this problem using it.takewhile but there as its just iterating through the file, I realized the `ftell()` inconsistency – Abhijit Jan 15 '13 at 15:48
  • @Abhijit -- but `strip` will match if there is trailing whitespace. I don't think that the `\n` is a problem (even on platforms where the line ending is `\r\n` as python (I think) will convert it for you in a platform specific way. I don't have a windows machine though, so I can't *guarantee* that without searching through the docs ... – mgilson Jan 15 '13 at 15:51
  • @Abhijit -- The documentation on [`open`](http://docs.python.org/2/library/functions.html#open) states that "The default is to use text mode, which may convert `'\n'` characters to a platform-specific representation on writing and back on reading" – mgilson Jan 15 '13 at 15:57
  • @mgilson: I overlooked the fact that you were opening the file in text mode :-) – Abhijit Jan 15 '13 at 16:00
  • @Abhijit -- My typical attitude toward Windows is that it isn't an operating system. However, if I had been wrong about this one, I would have probably been pretty upset -- I already found out today that I've had an incorrect idea about descriptors for a few months :). Imagine my surprise if I've been wrong about `open` all this time as well! – mgilson Jan 15 '13 at 16:04
3

If the file is small then you can simply use str.replace():

>>> !cat abc.txt
xxxxx
yyyyy
zzzzz
ttttt

>>> with open("abc.txt") as f,open("out.txt",'w') as o:
    data=f.read()
    data=data.replace("xxxxx\nyyyyy","xxxxx\nyourline\nyyyyy")
    o.write(data)
   ....:     

>>> !cat out.txt
xxxxx
yourline
yyyyy
zzzzz
ttttt

For a huge file use mgilson's approach.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504