Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace a specific line in a file using Ruby

I have a text file (a.txt) that looks like the following.

open
close
open
open
close
open

I need to find a way to replace the 3rd line with "close". I did some search and most method involve searching for the line than replace it. Can't really do it here since I don't want to turn all the "open" to "close".

Essentially (for this case) I'm looking for a write version of IO.readlines("./a.txt") [2].

like image 933
Evilmuffin Avatar asked Mar 12 '16 14:03

Evilmuffin


2 Answers

How about something like:

lines = File.readlines('file')
lines[2] = 'close' << $/
File.open('file', 'w') { |f| f.write(lines.join) }
like image 188
Yam Marcovic Avatar answered Nov 07 '22 11:11

Yam Marcovic


str = <<-_
my
dog
has
fleas
_

FNameIn  = 'in'
FNameOut = 'out'

First, let's write str to FNameIn:

File.write(FNameIn, str)
  #=> 17

Here are a couple of ways to replace the third line of FNameIn with "had" when writing the contents of FNameIn to FNameOut.

#1 Read a line, write a line

If the file is large, you should read from the input file and write to the output file one line at a time, rather than keeping large strings or arrays of strings in memory.

fout = File.open(FNameOut, "w")
File.foreach(FNameIn).with_index { |s,i| fout.puts(i==2 ? "had" : s) }
fout.close

Let's check that FNameOut was written correctly:

puts File.read(FNameOut)
my
dog
had
fleas

Note that IO#puts writes a record separator if the string does not already end with a record separator.1. Also, if fout.close is omitted FNameOut is closed when fout goes out of scope.

#2 Use a regex

r = /
    (?:[^\n]*\n) # Match a line in a non-capture group
    {2}          # Perform the above operation twice
    \K           # Discard all matches so far
    [^\n]+       # Match next line up to the newline
    /x           # Free-spacing regex definition mode

File.write(FNameOut, File.read(FNameIn).sub(r,"had"))

puts File.read(FNameOut)
my
dog
had
fleas

1 File.superclass #=> IO, so IO's methods are inherited by File.

like image 1
Cary Swoveland Avatar answered Nov 07 '22 09:11

Cary Swoveland