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

使用Ruby查找字符串的前一个匹配项,ruby,Ruby,我正在使用Ruby创建一些基本的工作辅助实用程序。我遇到了一个我并不需要解决的问题,但好奇心占据了我的上风 我想能够做的是搜索文件的内容,从一个特定的行开始,并找到之前出现的第一个字符串 例如,如果将以下文本保存在文件中,我希望能够从第4行开始搜索“创建过程”,并返回/输出“创建过程sp\U合并表” 搜索内容不是一项挑战,但要指定一条起跑线——不知道。然后向后搜索。。。嗯 感谢您的帮助 蒂亚 我想你必须逐行阅读文件 那么,跟随就行了 flag=true if flag &&

我正在使用Ruby创建一些基本的工作辅助实用程序。我遇到了一个我并不需要解决的问题,但好奇心占据了我的上风

我想能够做的是搜索文件的内容,从一个特定的行开始,并找到之前出现的第一个字符串

例如,如果将以下文本保存在文件中,我希望能够从第4行开始搜索“创建过程”,并返回/输出“创建过程sp\U合并表”

搜索内容不是一项挑战,但要指定一条起跑线——不知道。然后向后搜索。。。嗯

感谢您的帮助


蒂亚

我想你必须逐行阅读文件

那么,跟随就行了

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

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

# 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
#伪代码
行号=0
而行号<起始行
从文件中读取行
如果在此行中找到内容
上次看到=行号或文件偏移量
结束
行号+=1
结束
最后一次见面时回来
恐怕你得一行一行地浏览这个文件,除非你在上面有索引,指向行的开头。这将使循环稍微简单一点,但以向后的方式处理文件更困难(除非将整个文件保存在内存中)。

编辑:

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

向后搜索的好处是,您只需读取文件的第一个块,直到指定的行号为止。为了接近对方,你离起跑线越来越近,如果你找到了一条匹配的,你就忘了原来的那条。。您在开始时仍然读取了一些冗余数据,但至少是O(n)

当然,请记住,此文件的大小在回答您的问题时起着重要作用

如果你真的想认真一点,你可以深入课堂——看起来这可能是最终的解决方案。未经测试,只是一个想法

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
1) 将整个文件读入字符串。
2) 反转文件数据字符串。
3) 反转搜索字符串。
4) 向前搜索。记住要匹配行尾而不是行首,并且要从位置end减去N开始,而不是从N开始


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

你有没有尝试过这个问题?如果是这样的话,以任何代码或任何伪代码作为起点?否则我们基本上是在为你做一切。我无意冒犯你!通常
\n
是新行字符。可以对字符进行计数以指定行。如果您在文件中找到第二个
\n
,则它后面的字符是第3行的第一个字符。无意冒犯-我当然不希望你们为我做这项工作,正如我前面所说的-我这样做的成本可能大于好处。这实际上是更大工作的一小部分,我使用了一些不同的方法(从TSQL脚本到grep组合)对其进行了研究。我真的很喜欢Ruby,下一步我就开始了。我比什么都好奇。我曾考虑过将文件加载到数组中,然后向后迭代,但这似乎缺乏Ruby解决方案中常见的优雅。我的尝试是丑陋的-我希望有一个公主。我很感激我的尝试,我想这样做。但实际上,我必须从指定的起始行开始逐行向后读取文件。这意味着将整个东西加载到一个数组中,然后向后移动。做得好,但丑。如上所述,我只是想通过这个学习一些更优雅的文件操作方法。谢谢你的尝试!砰!!!我喜欢!你最初的解决方案是我的大脑第一次去的地方——你新的和改进的解决方案是我想要我的大脑去的地方。似乎没有任何类型的文件/字符串查找调用可以修改以满足我的要求。就我而言,这个答案是次好的答案。非常感谢你的帮助!再次更新答案-似乎您可以执行类似
File.lineno=my\u line\u number
等操作。另外,
seek
read
可能是您的朋友,但除非您的文件非常大,否则这可能会有点过分。)
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