IO.gets steps through a file one line at a time. However, I cannot
figure out how to (once i find something i need in the file) go
backwards line by line through that file until i find something else. I
thought possibly setting IO.lineno to the line before the current line
that would work, but I think I just misunderstood what lineno was for.
Anyone know a good way to do this?
Thanks
On 12.09.2009 17:57, M. Q. wrote:
IO.gets steps through a file one line at a time. However, I cannot
figure out how to (once i find something i need in the file) go
backwards line by line through that file until i find something else. I
thought possibly setting IO.lineno to the line before the current line
that would work, but I think I just misunderstood what lineno was for.
Anyone know a good way to do this?
One option is to create an Array of positions obtained via IO#tell while
you go along. Then you can move backwards to every line start.
Something like
File.open “foo” do |io|
idx = [io.tell]
while l = io.gets
p l
idx << io.tell
end
end
Cheers
robert
M. Q. wrote:
IO.gets steps through a file one line at a time.
As does IO.foreach. And IO.foreach’s block terminates naturally when
the end of the file is reached:
IO.foreach(“data.txt”) do |line|
puts line
end
I thought possibly setting IO.lineno to the line before the current
line that would work, but I think I just misunderstood what lineno
was for.
$ ri IO.lineno
-------------------------------------------------------------- IO#lineno
ios.lineno => integer
Returns the current line number in _ios_. The stream must be opened
for reading. +lineno+ counts the number of times +gets+ is called,
rather than the number of newlines encountered. The two values will
differ if +gets+ is called with a separator other than newline. See
also the +$.+ variable.
f = File.new("testfile")
f.lineno #=> 0
f.gets #=> "This is line one\n"
f.lineno #=> 1
f.gets #=> "This is line two\n"
f.lineno #=> 2
The key line in the description is:
lineno counts the number of times gets is called
It’s no different than if you wrote:
lineno = 0
IO.foreach(“data.txt”) do |line|
lineno += 1
puts “#{lineno}: #{line}”
if lineno==1
lineno = 30
end
end
data.txt:
hello
world
goodbye
–output:–
1: hello
31: world
32: goodbye
lineno is just a counter–it has no affect on the actual file pointer,
which marks the location of the current position in the file.
Anyone know a good way to do this?
prev_lines = []
IO.foreach(“data.txt”) do |line|
if line =~ /good/
prev_lines.reverse_each do |prev_line|
if prev_line =~ /hel/
puts prev_line
prev_lines = []
end
end
end
prev_lines << line
end
7stud – wrote:
M. Q. wrote:
IO.gets steps through a file one line at a time.
As does IO.foreach. And IO.foreach’s block terminates naturally when
the end of the file is reached:
IO.foreach(“data.txt”) do |line|
puts line
end
…and foreach closes the file for you automatically.
7stud – wrote:
Anyone know a good way to do this?
prev_lines = []
IO.foreach(“data.txt”) do |line|
if line =~ /good/
prev_lines.reverse_each do |prev_line|
if prev_line =~ /hel/
puts prev_line
prev_lines = []
end
end
end
prev_lines << line
end
Of course, if you’re files aren’t really big (e.g. 1+ GB), you can
simply read the whole file into memory:
lines = File.readlines(“data.txt”)
lines.each do |line|
if line =~ /good/
lines.reverse_each do |prev_line|
if prev_line =~ /hel/
puts prev_line
end
end
end
end