ralfthewise has asked for the wisdom of the Perl Monks concerning the following question:

Saw something similar to this topic on the Monastery Gates but thought I'd ask all the same, because I'm not really getting anywhere.

I want to do the following from a text file with entries delimited by :'s
1. read a line from a text file
2. first word(s) becomes the hash name
3. next 4 words go into key,value pairs
4. repeat to EOF

ex:
name: bob: jane: joe: sue:
name2: john: me: oh: my:

So, I want a hash called name. With key,value pairs to look something like first,bob....second,jane and so on. And a second hash called name2. With key,value pairs to be first, john....second,me...etc.

I've been playing with regexes and splits with varying degrees of a total lack of success.

John

Replies are listed 'Best First'.
Re: parsing text file into a hash?
by davorg (Chancellor) on Jun 15, 2001 at 20:17 UTC
(Ovid - a slice of hash, anyone?) Re: parsing text file into a hash?
by Ovid (Cardinal) on Jun 15, 2001 at 23:08 UTC

    A hash slice might be handy here:

    use strict; use warnings; use Data::Dumper; my %hash; while ( <DATA> ) { chomp; my @vals = split ':'; if ( scalar( @vals ) % 2 ) { @{ $hash{$vals[0]} }{ @vals[1..($#vals/2)] } = @vals[( ($#vals +/2)+1 )..$#vals]; } else { print "Uneven number of elements: $_\n"; } } print Dumper %hash; __DATA__ users:john:mary:1:2 cities:Portland:Amsterdam:New York:Pretty Cool:Awesome:Ugh! misc:foo:bar:baz:Ovid

    Read a line and split on the colons. If there are an uneven number of elements (not counting the first), then skip. Otherwise, the first element becomes the hash primary key and the rest of the array is divided in two. The first half becomes the keys to a hash ref identified by $vals[0] and the second half becomes the values.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: parsing text file into a hash?
by runrig (Abbot) on Jun 15, 2001 at 20:14 UTC
    You are looking for symbolic references, which means not using 'use strict', which is usually a bad idea. Why not store all the data in one hash of hashes?
    use strict; my %names; while (<>) { my ($label, $name1, $name2, $name3, $name4) = split /:/; $names{$label}{$name1} = $name2; $names{$label}{$name3} = $name4; }
    And the non strict (bad, dangerous, don't do this) version:
    # Untested, because I rarely use symbolic refs :) while (<>) { my ($label, $name1, $name2, $name3, $name4) = split /:/; $$label{$name1} = $name2; $$label{name3} = $name4; }
      That won't produce quite what he specifies:
      yours makes %names = name => bob => jane joe => sue name2 => john => me oh => my
      but his text seems to say he wants this:
      yours makes %names = name => first => bob second => jane third => joe fourth => sue name2 => first => john second => me third => oh fourth => my
      if this is really what is wanted, try this slight change:
      use strict; my %names; while (<>) { my ($label, $name1, $name2, $name3, $name4) = split /:/; $names{$label}{"first"} = {$name1} $names{$label}{"second"} = $name2; $names{$label}{"third"} = {$name3} $names{$label}{"fourth"} = $name4; }
      'The fickle fascination of and Everlasting God' - Billy Corgan, The Smashing Pumpkins
        Hey, I couldn't get it to compile until I changed the following
        {
        my ($label, $name1, $name2, $name3, $name4) = split /:/;
        $names{$label}{"first"} = $name1;
        $names{$label}{"second"} = $name2;
        $names{$label}{"third"} = $name3;
        $names{$label}{"fourth"} = $name4;
        }
        ...note the changes on $name1 and $name3....{$namex} to $namex;. I'm new at this, so should I have just left it alone? Is there something I just don't know? john