代码之家  ›  专栏  ›  技术社区  ›  Bobby B

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

  •  1
  • Bobby B  · 技术社区  · 15 年前

    我正在使用Ruby创建一些基本的工作帮助实用程序。我遇到了一个不需要解决的问题,但好奇心是我最好的选择。

    我希望能够搜索一个文件的内容,从一个特定的行开始,然后查找字符串的前一个匹配项。

    例如,如果我将以下文本保存在一个文件中,我希望能够从第4行开始搜索“创建过程”,并让这个返回/输出“创建过程sp_merge_table”

    CREATE PROCEDURE sp_MERGE_TABLE
    AS
     SOME HORRIBLE STATEMENT
     HERE
    
    CREATE PROCEDURE sp_SOMETHING_ELSE
    AS
     A DIFFERENT STATEMENT
     HERE
    

    搜索内容不是一个挑战,而是指定一个起点——不知道。然后向后搜索…好。。。

    感谢您的帮助!

    蒂亚!

    4 回复  |  直到 12 年前
        1
  •  0
  •   Jeriko    15 年前

    编辑:

    我刚刚有了一个更好的主意,但无论如何我还是要把旧的解决方案包括进去。

    向后搜索的好处意味着您只需要读取文件的第一个块,直到指定的行号。为了接近,你越来越接近起跑线,如果你找到了一个匹配,你就忘了旧的。您在开始时仍然会读取一些冗余数据,但至少是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
    
        2
  •  1
  •   Salil    15 年前

    我想你得一行一行地读文件

    那么下面的工作就可以了

      flag=true
      if flag && line.include?("CREATE PROCEDURE")
        puts line
        flag=false
      end 
    
        3
  •  1
  •   szeryf    15 年前

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

    # 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
    

    恐怕您必须逐行地处理文件,除非您在文件上有索引,指向行的开头。这会使循环变得简单一点,但是以向后的方式处理文件会比较困难(除非您将整个文件保存在内存中)。

        4
  •  0
  •   ChrisPhoenix    12 年前

    1)将整个文件读入一个字符串。
    2)反转文件数据字符串。
    3)反转搜索字符串。
    4)向前搜索。记住要匹配行尾而不是行首,并且从位置end-minus-n开始而不是从n开始。

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