Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Parsing data into an Array of Hashes

by nimdokk (Vicar)
on Sep 18, 2003 at 12:44 UTC ( #292371=perlquestion: print w/ replies, xml ) Need Help??
nimdokk has asked for the wisdom of the Perl Monks concerning the following question:

I'm seeking some guidance here. I have reports that I would like to parse into hashes to make for easier access of the data. The raw data would look like this:
Field1= a value,Field2= another value,
Field3= yet another value

(note these would all be one long line)

This would be one entry in the raw data file, each entry ends with a newline. It looks to me like an array of hashes. I know that I need to first split the line based on the comma. Then take and split each key=value pair and feed it into a hash. I don't really have any sample code to display at the moment. I'm mainly looking for suggestions on how to do the data manipulations of this kind.

Thanks in advance.


"Ex libris un peut de tout"

Comment on Parsing data into an Array of Hashes
Re: Parsing data into an Array of Hashes
by Wonko the sane (Deacon) on Sep 18, 2003 at 12:57 UTC
    This is one way to do it.
    #!/usr/local/bin/perl5.6.0 -w use strict; use Data::Dumper; my @records; while ( my $entry = <DATA> ) { my %rec = map { /(\S+)\s*=\s*([^\n\r]+)$/ } split( /,/, $entry ); push( @records, \%rec ); } print Dumper( \@records ); __DATA__ Field1= a value,Field2= another value, Field3= yet another value Field1= a value,Field2= another value, Field3= yet another value Field1= a value,Field2= another value, Field3= yet another value

    Best Regards,
    Wonko

Re: Parsing data into an Array of Hashes
by jonadab (Parson) on Sep 18, 2003 at 13:04 UTC

    Assuming that there are no _extra_ commas or equal signs besides the ones that separate key/value pairs and separate the keys from the values, ...

    my @stuff; while (<FILEHANDLE>) { chomp; push @stuff, { map {split /\s*=\s*/} split /,\s*/ } }

    But don't just copy this code if you don't understand it, especially if this is going into something you'll have to maintain. Let's break that down into something more verbose...

    Also, be aware that if there are any anomalies in the input, such as any missing or extra commas or equal signs, this code will produce quite strange results. I believe there is an extra argument you can optionally pass to split to limit the number of pieces it will split things into, which may be of value here. I'd look it up, but my camel is at home and I'm not. Perhaps someone else can reply and confirm whether it is the third argument as ISTR.

    update: Added \s* and chomp in several places to better trim whitespace.

    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
      Thanks, that helps. I was working somewhat along these lines already but wasn't quite getting things put into the right spots. I'll poke around a bit more with this as the days go by (this is really a side project that I'm working on when I get frustrated with other things :)


      "Ex libris un peut de tout"
Re: Parsing data into an Array of Hashes
by thinker (Parson) on Sep 18, 2003 at 13:06 UTC

    Hi nimdokk

    You could try something like

    #!/usr/bin/perl use strict; use warnings FATAL => 'all'; use Data::Dumper; open DATA, "filename" or die $!; my @AoH; for (<DATA>){ my %hash; %hash = map { split '=' } split ','; push @AoH, \%hash; } print Dumper \@AoH;

    cheers

    thinker

Re: Parsing data into an Array of Hashes
by kesterkester (Hermit) on Sep 18, 2003 at 13:10 UTC
    This is a little clunky, and could use some whitespace-stripping, but it'll get across the general idea:

    The while loop loops over your data, and the split breaks your line into a list of comma- and equal sign-separated items.

    This list is then converted into an anonymous hash with the {} operator, and that hash is pushed onto the array @structure.

    Note that this will work incorrectly if your values or field names have "="s or ","s in them.

    #!perl use warnings; use strict; use Data::Dumper; my @structure; while (<DATA>) { chomp; push @structure, { split /,|=/ }; } print Dumper \@structure; __DATA__ Field1= a value,Field2= another value, Field3= yet another value Field1= a second value,Field2= another second value, Field3= yet anoth +er second value
Re: Parsing data into an Array of Hashes
by Abigail-II (Bishop) on Sep 18, 2003 at 13:14 UTC
    As a one-liner:
    my @data = map {chomp; +{/([^=]+)=([^,]+),?/g}} <>;

    Abigail

Re: Parsing data into an Array of Hashes
by svsingh (Priest) on Sep 18, 2003 at 13:14 UTC
    No one's suggested it yet, so I thought I'd try something. I was able to do this without splitting the data. I just looped it through a regex. If your data is all on one line, then you don't even need the outer while loop. Hope this helps.
    #!/usr/local/bin/perl -w use strict; use Data::Dumper; my %records; while ( <DATA> ) { chomp; while ( m| (\w+)\s* = \s*([^,]+)\s* |gx ) { $records{$1} = $2; # add to hash } } print Dumper( \%records ); __DATA__ F1=D1, F2 = D2, F3= D3, F4 =D4, F5 = D5
    Ouput:
    $VAR1 = { 'F2' => 'D2', 'F3' => 'D3', 'F4' => 'D4', 'F5' => 'D5', 'F1' => 'D1' };

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://292371]
Approved by gjb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (8)
As of 2014-09-22 06:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (182 votes), past polls