Ruby:逐行匹配范围

时间:2013-07-03 20:22:33

标签: ruby regex range multiline

有没有办法在Ruby中执行以下Perl结构?

while( my $line = $file->each_line() ) {
  if($line =~ /first_line/ .. /end_line_I_care_about/) {
   do_something; 
   # this will do something on a line per line basis on the range of the match
  }
}

在ruby中会读到类似的内容:

file.each_line do |line|
  if line.match(/first_line/) .. line.match(/end_line_I_care_about/)
     do_something;
     # this will only do it based on the first match not the range.
  end
end

将整个文件读入内存不是一种选择,我不知道该范围的大块有多大。

编辑:

感谢您的回答,我得到的答案与我最初的代码基本相同。我遇到的问题是“它可以测试正确的操作数,并在同样的评估中变为错误(如在awk中),但它仍然返回true一次。”

“如果您不希望它在下一次评估之前测试正确的操作数,就像在sed中一样,只需使用三个点(”...“)而不是两个。在所有其他方面,”......“表现就像“......”一样。“

我正在标记正确答案,指出我可以在同一个电话中关闭'..'。

作为参考,我使用的代码是:

file.each_line do |line|
  if line.match(/first_line/) ... line.match(/end_line_I_care_about/)
     do_something;
  end
end

3 个答案:

答案 0 :(得分:5)

是的,Ruby支持触发器:

str = "aaa
ON
bbb
OFF
cccc
ON
ddd
OFF
eee"
str.each_line do |line|
  puts line if line =~ /ON/..line =~ /OFF/
 #puts line if line.match(/ON/)..line.match(/OFF/) #works too
end

输出:

ON
bbb
OFF
ON
ddd
OFF

答案 1 :(得分:1)

我不完全清楚Perl代码的确切语义,假设你想要完全一样。 Ruby确实具有类似的外观或工作方式,或者可能相同:作为条件的范围可用作切换。您提供的代码与我想象的完全一样。

然而,有几点需要注意:

  1. 即使达到最终条件,在您到达文件末尾之前,行仍会一直被读取。如果您希望结束条件接近大文件的开头,这可能是性能考虑因素。

  2. 可以多次触发启动条件,重新打开“开关”,执行do_something并再次测试结束条件。如果您的条件足够具体,或者如果您想要这种行为,这可能会很好,但是需要注意这一点。

  3. 可以在调用开始条件的同时调用结束条件,只为一行提供true。

  4. 这是另一种选择:

    started = false
    
    file.each_line do |line|
      started = true if line =~ /first_line_condition/
      next unless started
      do_something()
      break if line =~ /last_line_condition/
    end
    

    该代码读取文件的每一行,直到达到开始条件。然后它会执行您喜欢的任何处理,直到您到达与您的结束条件相匹配的行,此时它会跳出循环,从文件中不再读取任何行。

答案 2 :(得分:0)

此解决方案最接近您的需求。它几乎看起来像Perl,但这个有效的Ruby(虽然触发器操作员有点气馁)。 文件是逐行读取的,它没有完全加载到内存中。

File.open("my_file.txt", "r").each_line do |line|
  if (line =~ /first_line/) .. (line =~ /end_line_I_care_about/)
    do_something
  end
end

括号是可选的,但它们提高了可读性。