http://www.perlmonks.org?node_id=93620

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

Hi Monks,
Here is my mystery:
I'd like to assign a hash to a "complexe" (read big) regular expression.

m/(ID)(name)(email)(title)(date)(...)/  # simplify

I know that I can do that:

(ID, name, email, title, date, ...) = /(ID)(name)(email)(title)(date)(...)/;

but I'd like to do something like that:

%hash{ID} = (name, email, title, date, ...) = map {/(ID)(name)(email)( +title)(date)(...)/} @lignes; # Get parameters for each line... Like CSV files. But ID is not in the + same list

Something better could be to use OObject but hey, I am lost...

I hope I am clear enougth,
help will be greetfully appreciate :)

BobiOne KenoBi ;)

Replies are listed 'Best First'.
(bbfu) Re: Hash asignement with RE and map()
by bbfu (Curate) on Jul 03, 2001 at 22:45 UTC

    my %hash = map { /(ID)(name)(email)(title)(date)(...)/ && do { ($1, [$ +2, $3, $4, $5, ...]) } } @lines; # or, equivalently: my %hash = map { ($1, [$2, $3, $4, $5, ...]) if(/(ID)(name)(email)(tit +le)(date)(...)/ } @lines;

    bbfu
    Seasons don't fear The Reaper.
    Nor do the wind, the sun, and the rain.
    We can be like they are.

      I would be inclined to write it as follows, so as to avoid the explicit enumeration of match groups:
      my %hash = map { shift @$_ => [ @$_ ] } map [ /(ID)(name)(email)(title)(date)(...)/ ], @lines;
         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print
Re: Hash asignement with RE and map()
by dragonchild (Archbishop) on Jul 03, 2001 at 22:43 UTC
    If I'm right, you've got some string which parses out into an ID, then a series of fields. You want to create a hash with key of ID and value being some hashref, pointing to a hash with key of name/email/etc and value being the value.

    The basic code for this would be something like:

    ($ID,$name,$email,$title,$date,...) = /(ID)(name)(email)(title)(date)( +...)/; $hash{$ID}{name} = $name; $hash{$ID}{email} = $email; ...

    Now, what you're doing is, essentially, assigning a hash slice. Now, if you don't know, a hash slice is done something like:

    my @keys = ('a', 'b', 'c'); my @vals = (1, 2, 3); my %hash; @hash{@keys} = @vals;

    At this point, $hash{a} == 1, etc.

    For a hash of hashes, I think the syntax is something like:

    my @keys = ('a', 'b', 'c'); my @vals = (1, 2, 3); my %hash; @($hash{key}}{@keys} = @vals;

    But, please test this out.

    To marry this with the code you have right now, I'd do something like:

    my @keys = ('name', 'email', 'title', ...); ($ID, @vals) = /(ID)(name)(email)(title)(date)(...)/; @{$hash{$ID}}{@keys} = @vals;
      Thank you for your explanation, it will be usefull.
      But bbfu got the hint ;)

      Thanks all ! This make it a bit clearer now.

      BobiOne KenoBi ;)

Re: Hash asignement with RE and map()
by John M. Dlugosz (Monsignor) on Jul 03, 2001 at 22:39 UTC
    my @results= m/ ... /; my $ID= shift @results; $hash{$ID}= [@results];
    Something like that?

    —John

(dkubb) Re: (2) Hash asignement with RE and map()
by dkubb (Deacon) on Jul 04, 2001 at 06:49 UTC

    Others in this node have outlined the technique, but I'd like to present the concept in the context of a working example:

    #!/usr/bin/perl -w use strict; use Data::Dumper qw(Dumper); my %hash; while (my $line = <DATA>) { next unless my ($id, @row) = $line =~ /^(\d+) (\w+) (\S+) (\w+) (\w+)$/; @{$hash{$id}}{qw(name email title date)} = @row; } print Dumper(\%hash); __DATA__ 1 merlyn merlyn@perlmonks.org saint today 2 tilly tilly@perlmonks.org saint today 3 tye tye@perlmonks.org saint today 4 jcwren jcwren@perlmonks.org saint today

    This will iterate over the file handle, and attempt to match the $line with a regex. (You'll note that I changed the regex slightly to work with the data) If there is no match, then it will skip over the line. If there is a match, it will assign to a hash slice underneath $hash{$id}. It's the equivalent of:

    my %hash; my %account; @account{ qw(name email title date) } = @row; $hash{$id} = \%account;

    One advantage of the first example is that you are doing it in a single step, without using any 'Synthetic' Code.

Re: Hash asignement with RE and map()
by thpfft (Chaplain) on Jul 03, 2001 at 23:05 UTC

    how about s///e? eg:

    s/(ID)(name)(email)(title)(date)(...)/%{$hash{$1}}=($2,$3,$4,$5)/ie for @lines;

    Or something like that. The exact form will depend on whether your re matches keys and values or just values.

    update: added caveat