Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Backtracking through a file

56 views
Skip to first unread message

M. Q.

unread,
Sep 12, 2009, 11:57:55 AM9/12/09
to
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
--
Posted via http://www.ruby-forum.com/.

Robert Klemme

unread,
Sep 12, 2009, 12:07:49 PM9/12/09
to
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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

7stud --

unread,
Sep 12, 2009, 3:27:48 PM9/12/09
to
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 --

unread,
Sep 12, 2009, 3:30:54 PM9/12/09
to
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 --

unread,
Sep 12, 2009, 3:44:14 PM9/12/09
to
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

0 new messages