On 24.01.2007 17:02, William James wrote:
> 
> On Jan 24, 9:33 am, Paul van Delst <Paul.vanDe... / noaa.gov> wrote:
>> Hello,
>>
>> As I use ruby more and more for things, I find myself creating "Config" classes, filling
>> them with data read from a simple text file, and then passing instances of config around
>> to do all the work. What I would like to get some advice on, or links to, is ruby-ish
>> methods of reading/parsing text files.
>>
>> A lot of text files have, for example, some sort of header that says how much data is
>> coming, followed by the data itself, e.g.
>>
>> Number of data points: 5
>> 1 2
>> 3 4
>> 5 6
>> 7 8
>> 9 0
>> Number of data points: 2
>> 10 20
>> 11 21
>> Number of data points: 20
>> 1 2
>> 2 3
>> ..etc..
>>
>> Or, svn log output where the header line says how many lines of log message follow.
>>
>> I find I'm struggling to figure out a tidy way to read these sorts of files. If, for
>> example, I iterate over the lines,
>>
>> IO.readlines(file_name).each do |line|
>>    ...parse the line
>> end
>>
>> How do I take advantage of the fact that the "header" line tells me how much actual data
>> follows before the next header? I.e. I discover that I need to read 5 point so I read 5
>> points and the next line that is parsed in the above iteration is the next header line.
>> Sort of short-circuiting the iteration.
>>
>> The solution I've come up with so far is to use "sentinel" values that flag what is to
>> come, but it's yuckily kludgy. Any tips from the 'sperts?
>>
>> Apologies if this is a CS101 type of question.
>>
>> cheers,
>>
>> paulv
>>
>> --
>> Paul van Delst             Ride lots.
>> CIMSS @ NOAA/NCEP/EMC               Eddy Merckx
> 
> 
> open('data1'){|handle|
>   while header = handle.gets do
>     header[ /\d+/ ].to_i.times {
>       p handle.gets
>     }
>   end
> }

Or test after the fact:

# untested
sets = []
current = nil
items = nil

File.foreach('data1') do |line|
   case line
     when /Number of data points: (\d+)/
       raise "Wrong amount" if current && current.size != items
       items = $1.to_i
       current = []
     else
       current << line.scan(/\d+/).map! {|x| x.to_i}
   end
end

raise "Wrong amount" if current && current.size != items

Regards

	robert