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

vinoth.ree has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have got an array with person details, from that array I need to get set of fields and values, some of the person may not have all the fields.

As there are no delimiter between each person, I tried below code like, first converted the array as single string and did regular expression matching.

As I am searching in a string, if a field is missing for a person its matching with next person value.

Example: if u run the above code you will get the below output

$VAR1 = { 'country' => '', 'name' => 'riya', 'address' => '', 'call' => '12345678', 'company' => '', 'age' => '34' }; $VAR1 = { 'country' => '', 'name' => 'vinoth', 'address' => '', 'call' => '12345678', 'company' => '', 'age' => '25' };

Here the riya user has no call field, but it taking the vinoth's call value, as per the regex its the expected behavior. how to avoid this behavior? I hope little change in the regex could resolve my issue.

use strict; use warnings; use Data::Dumper; my @fields=('age','company','call','address','country'); my @emp=('riya','vinoth'); my @array=( 'name riya', 'age 34', 'company xxxx', 'name vinoth', 'age 25', 'call 12345678', 'company xxxx', 'address asdd', 'country Ind'); my $details = join(',',@array); print "$details\n"; foreach my $name (@emp) { my %hash=(); $hash{'name'}=$name; foreach my $field (@fields){ if ($field eq 'name'){ if ($details =~/name\s*$name.*?,$field\s*(\S+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } elsif($field eq 'age'){ if ($details =~/name\s*$name.*?,$field\s*(\d+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } elsif($field eq 'company'){ if ($details =~/name\s*$name.*?,$field\s*(\S+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } elsif($field eq 'call'){ if ($details =~/name\s*$name.*?,$field\s*(\d+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } elsif($field eq 'country'){ print "$field\n"; if ($details =~/name\s*$name.*?,$field\s*(\S+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } elsif($field eq 'address'){ print "$field\n"; if ($details =~/name\s*$name.*?,$field\s*(\S+),/g) { $hash{$field}=$1; } else{ $hash{$field}=''; } } } print Dumper \%hash; }

All is well. I learn by answering your questions...

Replies are listed 'Best First'.
Re: Regex to capture field values
by choroba (Archbishop) on Jan 13, 2016 at 12:53 UTC
    When you encounter name, start a new hash.
    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; my @array = ( 'name riya', 'age 34', 'company xxxx', 'name vinoth', 'age 25', 'call 12345678', 'company xxxx', 'address asdd', 'country Ind', ); my %hash; my $name; while (@array) { my $line = shift @array; if (my ($field, $value) = $line =~ /^(.*) (.*)/) { $name = $value if 'name' eq $field; $hash{$name}{$field} = $value; } else { warn "Invalid line '$line'.\n"; } } print Dumper \%hash;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Regex to capture field values
by GotToBTru (Prior) on Jan 13, 2016 at 13:37 UTC

    If the purpose of @emp and @fields is to restrict the output to just those, then you can use them to filter.

    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; my @emp = ('riya','vinoth'); my @fields = ('age','company','call','address','country','name'); my %nameh = map { $_, 1 } @emp; my %fieldh = map { $_, 1 } @fields; my @array = ( 'name riya', 'age 34', 'company xxxx', 'fax 8765432109', 'name vinoth', 'age 25', 'call 12345678', 'company xxxx', 'address asdd', 'country Ind', ); my %hash; my $name; while (@array) { my $line = shift @array; if (my ($field, $value) = $line =~ /^(.*) (.*)/) { $name = $value if 'name' eq $field; $hash{$name}{$field} = $value if ($nameh{$name} && $fieldh{$fi +eld}); } else { warn "Invalid line '$line'.\n"; } } print Dumper \%hash;

    The output will omit the fax field I added to riya's data because it was not found in @fields.

    Update: added name to list of fields! This is what comes of not testing your code.

    But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

      Thanks GotToBTru.

      Yes, you are right I wanted to extract for the particular employees, that's why I have @emp array.


      All is well. I learn by answering your questions...
Re: Regex to capture field values
by Anonymous Monk on Jan 13, 2016 at 13:32 UTC
    functional style:
    use strict; use warnings; use Data::Dumper; use List::Util 'reduce'; my @array = ( 'name riya', 'age 34', 'company xxxx', 'name vinoth', 'age 25', 'call 12345678', 'company xxxx', 'address asdd', 'country Ind' ); my $hashes = reduce { my ( $key, $val ) = split / /, $b; push @$a, {} if $key eq 'name'; $a->[-1]{$key} = $val; $a; } [], @array; print Dumper $hashes;
    output:
    $VAR1 = [ { 'age' => '34', 'company' => 'xxxx', 'name' => 'riya' }, { 'call' => '12345678', 'address' => 'asdd', 'name' => 'vinoth', 'country' => 'Ind', 'company' => 'xxxx', 'age' => '25' } ];