Замените определенную строку в файле с помощью Ruby

У меня есть текстовый файл (a.txt), который выглядит следующим образом.

open
close
open
open
close
open

Мне нужно найти способ заменить 3-ю строку на «закрыть». Я провел некоторый поиск, и большинство методов включают поиск строки, а не ее замену. Не могу сделать это здесь, так как я не хочу превращать все «открытое» в «закрытое».

По сути (для этого случая) я ищу версию IO.readlines("./a.txt") для записи [2].


person Evilmuffin    schedule 12.03.2016    source источник


Ответы (2)


Как насчет чего-то вроде:

lines = File.readlines('file')
lines[2] = 'close' << $/
File.open('file', 'w') { |f| f.write(lines.join) }
person Yam Marcovic    schedule 12.03.2016

str = <<-_
my
dog
has
fleas
_

FNameIn  = 'in'
FNameOut = 'out'

Сначала запишем str в FNameIn:

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

Вот несколько способов заменить третью строку FNameIn на "had" при записи содержимого FNameIn в FNameOut.

#1 Прочитай строку, напиши строку

Если файл большой, вы должны читать из входного файла и записывать в выходной файл по одной строке за раз, а не хранить в памяти большие строки или массивы строк.

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

Проверим правильность написания FNameOut:

puts File.read(FNameOut)
my
dog
had
fleas

Обратите внимание, что IO#puts записывает разделитель записей если строка еще не заканчивается разделителем записей.1. Кроме того, если fout.close опущено, FNameOut закрывается, когда fout выходит за рамки.

#2 Используйте регулярное выражение

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, поэтому методы IO наследуются File.

person Cary Swoveland    schedule 12.03.2016