Удалить первые две строки файла с помощью ruby

#ruby

#ruby

Вопрос:

Мой скрипт считывает большие текстовые файлы и захватывает первую страницу с регулярным выражением. Мне нужно удалить первые две строки каждой первой страницы или изменить регулярное выражение, чтобы оно соответствовало 1 строке после строки == Страница 1 ==. Я включаю сюда весь скрипт целиком, потому что меня просили об этом в прошлых вопросах, а также потому, что я новичок в ruby и не всегда знаю, как интегрировать фрагменты в качестве ответов:

 #!/usr/bin/env ruby -wKU
require 'fileutils'

source = File.open('list.txt')
source.readlines.each do |line|
  line.strip!
  if File.exists? line
    file = File.open(line)
  end

  text = (File.read(line))
  match = text.match(/==Page 1(.*)==Page 2==/m)
  puts match
end
  

Комментарии:

1. Не могли бы вы выразить, что вы хотите, чтобы код делал? Для меня это выглядит так: я хочу удалить первые 2 строки для каждого файла, который включен в список, хранящийся в другом файле. Это правильно?

2. Извините — отредактировано. Вы правы, хотите удалить первые две строки каждого файла в моем списке.

3. Я обновил ответ. Надеюсь, я нашел вашу проблему 🙂 (уведомление через комментарий, потому что я не знаю, уведомляются ли спрашивающие об обновлениях ответов)

Ответ №1:

Теперь, когда вы обновили свой вопрос, мне пришлось удалить большую часть столь хорошего ответа 🙂

Я предполагаю, что основная суть вашей проблемы заключалась в том, что вы хотели использовать match[1] вместо match . Объект, возвращаемый Regexp.match методом ( MatchData ), может обрабатываться как массив, который содержит всю согласованную строку в качестве первого элемента и каждый подзапрос в следующих элементах. Итак, в вашем случае переменная match match[0] ) — это целая согласованная строка (вместе с метками ‘==Страница ..==’), но вы хотели только первое подвыражение, которое скрыто в match[1] .


Теперь о других, незначительных проблемах, которые я ощущаю в вашем коде. Пожалуйста, не обижайтесь, если вы уже знаете, что я говорю, но, возможно, другие извлекут выгоду из предупреждений.

Первая часть вашего кода ( if File.exists? line ) проверяла, существует ли файл, но ваш код просто открыл файл (не закрывая его!) и все еще пытался открыть файл несколькими строками позже.

Вместо этого вы можете использовать эту строку:

 next unless File.exists? line
  

Вторая вещь заключается в том, что программа должна быть готова справиться с ситуацией, когда файл не имеет меток страницы, поэтому он не соответствует шаблону. (Тогда переменная match была бы nil )

Третье предложение заключается в том, что можно использовать немного более сложный шаблон. Текущая строка ( /==Page 1==(.*)==Page 2==/m ) вернет содержимое страницы с пометкой конца строки в качестве первого символа. Если вы используете этот шаблон:

 /==Page 1==s*n(.*)==Page 2==/m
  

тогда подвыражение не будет содержать пробелов, размещенных в той же строке, что и текст ‘==Страница 1==`. И если вы используете этот шаблон:

 /==Page 1==s*n(.*n)==Page 2==/m
  

тогда вы будете уверены, что отметка ‘==Страница 2 ==’ начинается с начала строки.

И четвертая проблема заключается в том, что очень часто программисты (иногда включая меня, конечно) склонны забывать о закрытии файла после того, как они его открыли. В вашем случае вы открыли ‘исходный’ файл, но в коде не было source.close инструкции после цикла. Самый безопасный способ обработки файлов — это передача блока File.open методу, поэтому вы можете использовать следующую форму первых строк вашей программы:

 File.open('list.txt') do |source|
  source.readlines.each do |line|
  

…но в этом случае было бы чище написать просто:

 File.readlines('list.txt').each do |line|
  

Если взять все это вместе, код может выглядеть следующим образом (я изменил переменную line на fname для лучшей читаемости кода):

 #!/usr/bin/env ruby -wKU
require 'fileutils'

File.readlines('list.txt').each do |fname|
  fname.strip!
  next unless File.exists? fname

  text = File.read(fname)
  if match = text.match(/==Page 1==s*n(.*n)==Page 2==/m)
    # The whole 'page' (String):
    puts match[1].inspect
    # The 'page' without the first two lines:
    # (in case you really wanted to delete lines):
    puts match[1].split("n")[2..-1].inspect
  else
    # What to do if the file does not match the pattern?
    raise "The file #{fname} does NOT include the page separators."
  end
end