Ruby包括偷看?表现得像下一个

时间:2016-11-19 19:07:58

标签: ruby enumerator peek

我现在无法理解我自己的ruby脚本。如果我使用peek检查下一个位置的内容,打算不使用include?移动位置,则无论如何我的枚举器的位置都会移动到下一个位置。

例如:

print @file.each_line.peek
if @file.each_line.peek.include? 'State'
  ...

输出

State

但是这个:

if @file.each_line.peek.include? 'State'
  print @file.each_line.peek
  ...

输出

CO

我的文件内容看起来像

...
Extension Date
State
CO
COLORADO
...

我将按以下方式打开此文件:@file = File.open(file)并使用@file.each_line枚举器。

对我来说,这似乎使用@file.each_line.peek.include? 'State'实际上导致该位置移动一个。有谁知道这是为什么以及如何避免它?

如何重现

使用以下内容创建名为 test.txt 的文件:

Extension Date
State
CO
COLORADO

使用以下内容创建名为 test.rb 的文件:

file = File.open('./test.txt')
until file.each_line.next.include? 'Extension Date' do ; end
print file.each_line.peek
if file.each_line.peek.include? 'State'
end

当您使用ruby test.rb时,您应该获得输出State

如果然后移动第3行使其位于if块内,则输出(对我而言)为CO

2 个答案:

答案 0 :(得分:4)

这不是@file.each_line.peek # => "Extension Date\n" @file.each_line.peek # => "State\n" @file.each_line.peek # => "CO\n" @file.each_line.peek # => "COLORADO\n" @file.each_line.peek # => "\n" ,而是你如何获得你的枚举器(每次都是新的)。观察:

each_line

这里的问题是,当调用enum = @file.each_line enum.peek # => "Extension Date\n" enum.peek # => "Extension Date\n" enum.peek # => "Extension Date\n" enum.peek # => "Extension Date\n" enum.peek.include?('foo') # => false enum.peek # => "Extension Date\n" 时,会读取一行。并且由于文件位置在调用之间保持不变,所以第二次调用它时,它会再读一行。等等。

获取一次枚举器并坚持下去。

process.exit(<code>);

答案 1 :(得分:0)

让我们先将数据写入文件。

FName = "temp"

File.write FName, "Extension Date\nstate\nCO\nCOLORADO\n\n"

检查一下。

puts File.read FName
  # Extension Date
  # state
  # CO
  # COLORADO
  #

现在执行代码并添加一些puts语句。

file = File.open(FName)

loop do
  enum = file.each_line
  puts "enum = #{enum}"
  puts "enum's object id = #{ enum.object_id }"
  puts "file.pos = #{file.pos}"
  puts "enum.peek = #{enum.peek}"
  puts "enum.peek = #{enum.peek}"
end
file.close

打印以下内容。前五行是:

enum = #<Enumerator:0x007feb528d8bd8>
file.pos = 0
enum's object id = 70324339525100
enum.peek = Extension Date
enum.peek = Extension Date

文件位置(如上所示)最初为0。我们试图获取文件中的下一行,即"Extention Date\n"。 Ruby必须使文件指针前进以读取第一行代码。但是,在这样做之后,她没有将文件位置重置为零,如下所示(file.pos #=> 0 + "Extention Date\n".size => 15)。我们还看到第二个enum.peek的文件指针没有再次提前,这表明Ruby将该值保存在缓冲区中。

enum = #<Enumerator:0x007feb528d8868>
enum's object id = 70324339524660
file.pos = 15
enum.peek = state

创建了一个新的枚举器,从enum的返回值和更改的object_id都可以看出。此枚举器从文件偏移量15开始。 peek返回state\n将文件指针前进到15 +&#34;州\ n&#34; .size#=&gt; 21`(见下文)。

enum = #<Enumerator:0x007feb528d84f8>
enum's object id = 70324339524220
file.pos = 21
enum.peek = CO

从文件偏移21开始创建第三个枚举器。 peek返回CO\n,将文件指针前进到21 + "CO\n".size #=> 24

enum = #<Enumerator:0x007feb528d8188>
enum's object id = 70324339523780
file.pos = 24
enum.peek = COLORADO

创建第四个枚举器,从文件偏移24开始。 peek返回COLORADO\n,将文件指针前进到24 + "COLORADO\n".size #=> 33

enum = #<Enumerator:0x007feb528d3db8>
enum's object id = 70324339515100
file.pos = 33
enum.peek = 

从文件偏移33开始创建第五个枚举器。 peek返回\n,将文件指针前进到33 + "\n".size #=> 34

  # enum = #<Enumerator:0x007feb528d3a48>
  #   enum's object id = 70324339514660
  #   file.pos = 34

从文件偏移34开始创建第六个枚举器。 peek引发StopIteration异常,由Kernel#loop通过突破循环来处理。

显然,您不想继续创建新的枚举器。请执行以下操作。

file = File.open(FName)
enum = file.each_line

loop do
  line = enum.next
  puts line
end
file.close
  # Extension Date
  # state
  # CO
  # COLORADO

我使用Enumerator#next代替Enumerator#peek,因为对于文件,它们具有相同的效果,而next更能传达正在做的事情。

请注意,File.close经常被省略,因为Ruby会在文件句柄超出范围时关闭文件。

我建议你改用IO :: foreach:

File.foreach(FName) do |line|
  puts line
end
  # Extension Date
  # state
  # CO
  # COLORADO
  #

foreach也会逐行读取文件,但在退出块时会将其关闭。请注意,由于FileIOFile < IO #=> true)的子类,因此IO类方法通常使用File作为接收方编写。