使用Ruby查找字符串的第一个上一个匹配项

时间:2010-07-06 13:04:32

标签: ruby

我正在使用Ruby创建一些基本的工作辅助工具。我遇到了一个我不需要解决的问题,但好奇心对我来说是最好的。

我希望能够做的是搜索文件的内容,从特定行开始,找到第一个PREVIOUS字符串。

例如,如果我将以下文本保存在文件中,我希望能够从第4行开始搜索“CREATE PROCEDURE”并将此返回/输出“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

搜索内容不是一个挑战,而是指定起始线 - 不知道。然后向后搜索......好吧......

任何帮助都赞赏!

TIA!

4 个答案:

答案 0 :(得分:1)

我认为你必须逐行阅读文件行

然后将会工作

  flag=true
  if flag && line.include?("CREATE PROCEDURE")
    puts line
    flag=false
  end 

答案 1 :(得分:1)

如果性能不是一个大问题,你可以使用一个简单的循环:

# 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

我担心你必须在文件中逐行工作,除非你有一些索引,指向行的开头。这会使循环变得更简单,但以向后方式处理文件会更难(除非您将整个文件保留在内存中)。

答案 2 :(得分:0)

修改

我只是有一个更好的主意,但无论如何我都要包括旧的解决方案。

向后搜索的好处意味着您只需要读取文件的第一个块,直到指定的行号。对于接近度,你越来越接近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

答案 3 :(得分:0)

1)将整个文件读成字符串 2)反转文件数据字符串 3)反转搜索字符串 4)向前搜索。请记住匹配行尾而不是行首,并从头尾-N-而不是从N开始。

不是很快或没有效率,但它很优雅。或者至少聪明。