1

有没有办法在 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 中),但它仍然返回真一次。”

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

我将正确答案标记为指示我看到“..”可以在发出的同一个呼叫中关闭的答案。

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

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

3 回答 3

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
于 2013-07-03T20:40:16.927 回答
1

假设您想要完全相同,我对 Perl 代码的确切语义并不十分清楚。Ruby 确实有一些看起来和工作方式相似或相同的东西:作为条件的 Range 可以作为切换。您提供的代码完全按照我想象的方式工作。

但是,有一些警告:

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

  2. 可以多次触发开始条件,重新打开“开关”,do_something再次测试结束条件。如果您的情况足够具体,或者您想要这种行为,这可能没问题,但需要注意这一点。

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

这是一个替代方案:

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

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

于 2013-07-03T20:41:59.170 回答
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

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

于 2013-07-03T20:31:39.520 回答