#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