Изменить:
У меня была гораздо лучшая идея, но я все равно собираюсь включить старое решение.
Преимущество поиска в обратном направлении означает, что вам нужно только прочитать первый фрагмент файла до указанного номера строки. Что касается близости, вы становитесь все ближе и ближе к start_line, и если вы находите совпадение, вы просто забываете старое. Вы все еще читаете некоторые избыточные данные в начале, но по крайней мере это O (n)
path = "path/to/file"
start_line = 20
search_string = "findme!"
#assuming file is at least start_line lines long
match_index = nil
f = File.new(path)
start_line.times do |i|
line = f.readline
match_index = i if line.include? search_string
end
puts "Matched #{search_string} on line #{match_index}"
Конечно, имейте в виду, что размер этого файла играет важную роль в ответе на ваш вопрос.
Если вы хотите стать действительно серьезным, вы можете заглянуть в класс IO
- кажется, что это может быть окончательным решением. Непроверенный, просто мысль.
f = File.new(path)
start_line.downto(0) do |i|
f.lineno = i
break if f.gets.include?(search_string)
end
Оригинал:
Для исчерпывающего решения вы можете попробовать что-то вроде следующего. Недостатком является то, что вам нужно будет прочитать весь файл в память, но он учитывает продолжение снизу вверх, если он достигает вершины без совпадения. Непроверенные.
path = "path/to/file"
start_line = 20
search_string = "findme!"
#get lines of the file into an array (chomp optional)
lines = File.readlines(path).map(&:chomp)
#"cut" the deck, as with playing cards, so start_line is first in the array
lines = lines.slice!(start_line..lines.length) + lines
#searching backwards can just be searching a reversed array forwards
lines.reverse!
#search through the reversed-array, for the first occurence
reverse_occurence = nil
lines.each_with_index do |line,index|
if line.include?(search_string)
reverse_occurence = index
break
end
end
#reverse_occurence is now either "nil" for no match, or a reversed-index
#also un-cut the array when calculating the index
if reverse_occurence
occurence = lines.size - reverse_occurence - 1 + start_line
line = lines[reverse_occurence]
puts "Matched #{search_string} on line #{occurence}"
puts line
end