Использование Ruby для поиска первого предыдущего вхождения строки - PullRequest
1 голос
/ 06 июля 2010

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

То, что я хотел бы сделать, это выполнить поиск содержимого файла, начиная с определенной строки, и найти первое ПРЕДЫДУЩЕЕ вхождение строки.

Например, если в файле сохранен следующий текст, я бы хотел иметь возможность поиска «CREATE PROCEDURE», начиная со строки 4, и иметь этот возврат / вывод «CREATE PROCEDURE sp_MERGE_TABLE»

CREATE PROCEDURE sp_MERGE_TABLE
AS
 SOME HORRIBLE STATEMENT
 HERE

CREATE PROCEDURE sp_SOMETHING_ELSE
AS
 A DIFFERENT STATEMENT
 HERE

Поиск контента не является проблемой, но указание стартовой строки - не знаю. А потом поиск назад ... ну ...

Любая помощь на всех приветствуется!

ТИА!

Ответы [ 4 ]

1 голос
/ 06 июля 2010

Если производительность не является большой проблемой, вы можете просто использовать простой цикл:

# pseudocode
line_no = 0
while line_no < start_line
  read line from file
  if content_found in this line
    last_seen = line_no # or file offset
  end
  line_no += 1
end
return last_seen

Боюсь, вам придется работать построчно через файл, если у вас нет индекса над ним, указывающего на начало строк. Это сделало бы цикл немного проще, но работать с файлом в обратном порядке сложнее (если вы не храните весь файл в памяти).

1 голос
/ 06 июля 2010

Я думаю, что вы должны прочитать файл строка за строкой

тогда будет работать

  flag=true
  if flag && line.include?("CREATE PROCEDURE")
    puts line
    flag=false
  end 
0 голосов
/ 21 июля 2013

1) Прочитать весь файл в строку.
2) Переверните строку данных файла.
3) Обратный поиск строки.
4) Поиск вперед. Не забудьте сопоставить конец строки вместо начала строки и начинать с позиции конец-минус-N, а не с N.

Не очень быстро или эффективно, но элегантно. Или хотя бы умный.

0 голосов
/ 06 июля 2010

Изменить:

У меня была гораздо лучшая идея, но я все равно собираюсь включить старое решение.

Преимущество поиска в обратном направлении означает, что вам нужно только прочитать первый фрагмент файла до указанного номера строки. Что касается близости, вы становитесь все ближе и ближе к 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...