Давайте создадим входной файл. 1
fname_in = 'in'
File.write fname_in, <<~BITTER_END
1
00:00:00 :
renovation with a fully
2
00:00:01 :
assembled 38-foot long trec
3
00:00:03 :
skeleton, the exhibit offers a
4
00:00:04 :
modern approach to presentation
5
00:00:07 :
of more than 700 fossils with
6
00:00:08 :
the exhibit starting in the
BITTER_END
#=> 268
Мы можем прочитать этот файл по четыре строки за раз и для каждой группы из четырех строк запишите одну строку в выходной файл, где эта строка состоит из второй и третьей строк каждой группы из четырех строк.
fname_out = 'out'
File.open(fname_out, 'w') do |f|
File.foreach(fname_in, chomp: true).each_slice(4) {|_, line2, line3, _|
f.puts line2 + line3}
end
Давайте подтвердим, что выходной файл был
puts File.read(fname_out)
00:00:00 : renovation with a fully
00:00:01 : assembled 38-foot long trec
00:00:03 : skeleton, the exhibit offers a
00:00:04 : modern approach to presentation
00:00:07 : of more than 700 fossils with
00:00:08 : the exhibit starting in the
Я использовал метод IO :: foreach , чтобы построчно прочитать входной файл. (Это должен быть метод go для чтения текстовых файлов построчно). Вы можете увидеть из foreach
do c, что метод имеет две формы, одну с блоком и одну без. Я использовал последний, который возвращает перечислитель, потому что я хочу связать его с методом Enumerable # each_slice .
Давайте посмотрим, как работают эти перечислители.
enum1 = File.foreach(fname_in, chomp: true)
#=> #<Enumerator: File:foreach("in", chomp: true)>
enum1.next #=> "1"
enum1.next #=> "00:00:00 : "
enum1.next #=> "renovation with a fully"
enum1.next #=> ""
enum1.next #=> "2"
...
Опция chomp: true
заставляет foreach
убирать символ новой строки в конце каждой строки. См. Перечислитель # следующий .
Далее мы имеем:
enum2 = enum1.each_slice(4)
#=> #<Enumerator: #<Enumerator: File:foreach("in", chomp: true)
# >:each_slice(4)>
enum2.next
#=> ["1", "00:00:00 : ", "renovation with a fully", ""]
enum2.next
#=> ["2", "00:00:01 : ", "assembled 38-foot long trec", ""]
...
Сравните возвращаемые значения для вычислений enum1
и enum2
. Вы можете видеть, что enum2
можно рассматривать как составной перечислитель .
Элементы теперь генерируются с помощью enum2
и передаются в его блок, а значения присваиваются четырем блокам. переменные 2 :
line1, line2, line3, line4 = enum2.next
#=> ["1", "00:00:00 : ", "renovation with a fully", ""]
line1 #=> "1"
line2 #=> "00:00:00 : "
line3 #=> "renovation with a fully"
line4 #=> "" line1
Этот процесс разбиения массива, возвращенного enum2.next
, на четыре части называется Разложение массива . Это мощный и полезный инструмент, который может стать довольно сложным. 3
Теперь мы можем выполнить вычисление блока:
str = line2 + line3
#=> "00:00:00 : renovation with a fully"
, а затем f.puts str
для записи эта строка в выходной файл. См. IO # приводит к .
Остальные вычисления, начиная с:
line1, line2, line3, line4 = enum2.next
#=> ["2", "00:00:01 : ", "assembled 38-foot long trec", ""]
, аналогичны.
Обратите внимание, что я заменил блок переменные line1
и line4
с подчеркиванием ('_'
, допустимая локальная переменная), главным образом, чтобы сообщить читателю, что эти переменные не используются в расчете блока. Это обычная практика. Иногда вместо этого вы можете увидеть |_line1, line2, line3, _line4|
, что означает то же самое.
Вот второй способ построения fname_out
:
File.open(fname_out, 'w') do |f|
File.foreach(fname_in, chomp: true) do |line|
case line
when /\A\d+\z/
str = ''
when ""
f.puts str
else
str << line
end
end
end
Наконец, если файл не слишком большой, мы может просто проглотить его в память, используя File::read
, а затем использовать String # scan с регулярным выражением, чтобы вытащить соответствующие строки, которые затем необходимо очистить, удалив символы новой строки.
File.read(fname_in).
scan(r).
map { |s| s.delete("\n") }
, где регулярное выражение выглядит следующим образом:
r =
/
^ # match the beginning of a line
\d{2}: # match two digits followed by a colon
.+? # match one or more characters lazily
(?=\n\n) # the match is to be followed by two newlines
/mx # multiline and free-spacing regex definition modes
1. Для подтверждения правильности написания файла выполните puts File.read(fname_in)
. См. IO :: write и IO :: read . IO методы класса часто вызываются для класса File , как я это сделал. Это допустимо, потому что File.superclass #=> IO
, поэтому File
наследует методы IO
.
2. Перед этим нам нужно выполнить enum2.rewind
. См. Перечислитель # перемотка .
3. Если, например, у нас есть a, (b, (c, d)) = [1, [2, [3, 4]]]
, то a
, b
, c
и d
соответственно будут установлены равными 1
, 2
, 3
и 4
.