【问题标题】:Ruby peek with include? acts like nextRuby 窥视包含?像下一个
【发布时间】:2023-03-30 09:31:01
【问题描述】:

目前我无法理解自己的 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

【问题讨论】:

  • 感谢您的尝试,我将用一个小示例更新我的答案,供您使用

标签: ruby enumerator peek


【解决方案1】:

这不是.include?,而是您获取枚举器的方式(每次一个新的)。观察:

@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"

【讨论】:

  • 对不起,你能再解释一下吗?为什么每次调用each_line.peek 的行为都像next
  • 根据文档,我很困惑为什么当它说不应该移动位置时,它实际上被移动了:ruby-doc.org/core-2.3.1/Enumerator.html#method-i-peek
  • 同样,移动位置的不是 peek。这是each_lineEach time you call it, it reads a line
  • 这样是不是第一次调用就初始化了?
  • @JakeSmith:该方法称为each_line,您调用它来枚举行。大概,您希望第一行尽快传递给您的块。所以它读了一行,因为为什么不应该呢?
【解决方案2】:

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

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 #=&gt; 0 + "Extention Date\n".size =&gt; 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 + "state\n".size #=> 21`(见下文)。

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

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

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

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

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

从文件偏移量33 开始创建第五个枚举器。 peek 返回\n,将文件指针前进到33 + "\n".size #=&gt; 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 也逐行读取文件,但在退出块时将其关闭。请注意,因为FileIO (File &lt; IO #=&gt; true) 的子类,所以IO 类方法通常以File 作为接收者编写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    相关资源
    最近更新 更多