Ruby 用 include 查看?表现得像下一个
Ruby peek with include? acts like next
我现在无法理解我自己的 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'
实际上导致位置移动 1。有谁知道这是为什么以及我该如何避免它?
如何重现
创建一个名为 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
。
这不是 .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"
让我们先将数据写入文件。
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
的 return 值和更改后的 object_id
中都可以看出。此枚举器从文件偏移量 15
开始。 peek
returns state\n
将文件指针前进到 15
+ "state\n".size #=> 21`(见下文)。
enum = #<Enumerator:0x007feb528d84f8>
enum's object id = 70324339524220
file.pos = 21
enum.peek = CO
创建了第三个枚举器,从文件偏移量 21
开始。 peek
returns CO\n
, 将文件指针前进到 21 + "CO\n".size #=> 24
.
enum = #<Enumerator:0x007feb528d8188>
enum's object id = 70324339523780
file.pos = 24
enum.peek = COLORADO
创建第四个枚举器,从文件偏移量 24
开始。 peek
returns COLORADO\n
, 将文件指针前进到 24 + "COLORADO\n".size #=> 33
.
enum = #<Enumerator:0x007feb528d3db8>
enum's object id = 70324339515100
file.pos = 33
enum.peek =
创建了第五个枚举器,从文件偏移量 33
开始。 peek
returns \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 instead of Enumerator#peek 因为对于文件它们具有相同的效果并且 next
更好地传达了正在做的事情。
请注意,File.close
经常被省略,因为 Ruby 将在文件句柄超出范围时关闭文件。
我建议您改用 IO::foreach:
File.foreach(FName) do |line|
puts line
end
# Extension Date
# state
# CO
# COLORADO
#
foreach
也逐行读取文件,但在退出块时将其关闭。请注意,因为 File
是 IO
(File < IO #=> true
) 的子 class,所以 IO
class 方法通常用 File
作为接收者。
我现在无法理解我自己的 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'
实际上导致位置移动 1。有谁知道这是为什么以及我该如何避免它?
如何重现
创建一个名为 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
。
这不是 .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"
让我们先将数据写入文件。
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
的 return 值和更改后的 object_id
中都可以看出。此枚举器从文件偏移量 15
开始。 peek
returns state\n
将文件指针前进到 15
+ "state\n".size #=> 21`(见下文)。
enum = #<Enumerator:0x007feb528d84f8>
enum's object id = 70324339524220
file.pos = 21
enum.peek = CO
创建了第三个枚举器,从文件偏移量 21
开始。 peek
returns CO\n
, 将文件指针前进到 21 + "CO\n".size #=> 24
.
enum = #<Enumerator:0x007feb528d8188>
enum's object id = 70324339523780
file.pos = 24
enum.peek = COLORADO
创建第四个枚举器,从文件偏移量 24
开始。 peek
returns COLORADO\n
, 将文件指针前进到 24 + "COLORADO\n".size #=> 33
.
enum = #<Enumerator:0x007feb528d3db8>
enum's object id = 70324339515100
file.pos = 33
enum.peek =
创建了第五个枚举器,从文件偏移量 33
开始。 peek
returns \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 instead of Enumerator#peek 因为对于文件它们具有相同的效果并且 next
更好地传达了正在做的事情。
请注意,File.close
经常被省略,因为 Ruby 将在文件句柄超出范围时关闭文件。
我建议您改用 IO::foreach:
File.foreach(FName) do |line|
puts line
end
# Extension Date
# state
# CO
# COLORADO
#
foreach
也逐行读取文件,但在退出块时将其关闭。请注意,因为 File
是 IO
(File < IO #=> true
) 的子 class,所以 IO
class 方法通常用 File
作为接收者。