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

I'm very PERL illiterate, so please help.

I have a file that read in strings such as

AlarmForwarderServer.exe,app_common.dll,DsCommon.dll,DSGccCommon.dll,D +sRffCommon.dll,DsGccProxy.dll,DsRffProxy.dll,

this is the format per line, the exe followed by a list of dlls. I want to search for the .exe and pust it on @myarray with a [<exe name.}, then I want to keep parsing the string and put the dll under it.

I keep getting compile errors. Here is the code I have.

foreach $line (@exeDllLines) # loop thru list { chomp($line); # chop off trailing newlines #find exe print "$line"; if( $line =~ m/exe/ ) { $line = "[$line]"; push @dllarray, $line; } if( $line =~ m/dll/ ) { push @dllarray, $line; }
I know there is probably a one liner out there, but PERL is so new, I'm still coding as if in C++.

Thanks for the help

Edit: g0n Code tags round example data

Replies are listed 'Best First'.
Re: noob regexpression question
by polettix (Vicar) on Nov 07, 2005 at 16:42 UTC
    I keep getting compile errors.
    Try to put the following at the beginning of your script:
    use strict; use warnings; use diagnostics;
    and you should get better info about what's going wrong. At a first glance, you're missing the foreach closing brace. Please note that using strict obliges you to declare all your variables before you use them, which you should appreciate as a C++ programmer :)

    If each $line contains the whole stuff, you'll have hard times. You should probably split using "," as a separator, then iterate thru the elements:

    foreach my $line (@lines) { chomp $line; foreach my $element (split /,/ , $line) { my $extension = substr($element, -3) || ''; if ( $extension eq 'exe' ) { push @dllarray, "[$element]"; } elsif ( $extension eq 'dll' ) { push @dllarray, $element; } } }
    Note: CODE UNTESTED!!!

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
      The || '' doesn't help, and you'll fail for "foodll".
      ... my $extension = substr($element, -3) || ''; if ( $extension eq 'exe' ) { ... elsif ( $extension eq 'dll' ) ...
      should be
      ... my $extension = substr($element, -4); if ( $extension eq '.exe' ) { ... elsif ( $extension eq '.dll' ) ...
        D'ho, lucky me that I put the big "untested code" :) I was convinced that the substr function would return undef if the string was empty (like the middle element in "ciccio.exe,,pallo.dll"), but it is simply the empty string.

        I could agree on the second correction, but only on a robustness ground that seems not necessary in this case. Anyway, better being overprotective, especially when it's cheap and helps building the right attitude.

        Flavio
        perl -ple'$_=reverse' <<<ti.xittelop@oivalf

        Don't fool yourself.
Re: noob regexpression question
by sgifford (Prior) on Nov 07, 2005 at 16:40 UTC
    The code you have is missing the final, closing curly brace. If I add that in, this compiles fine.
Re: noob regexpression question
by jdporter (Paladin) on Nov 07, 2005 at 17:45 UTC

    Your code pushes the entire line onto the array for each match. Is that really what you want? Because that means a line such as the sample you gave causes two elements to be pushed onto the array:

    [AlarmForwarderServer.exe,app_common.dll,DsCommon.dll,DSGccCommon.dll, +DsRffCommon.dll,DsGccProxy.dll,DsRffProxy.dll,] AlarmForwarderServer.exe,app_common.dll,DsCommon.dll,DSGccCommon.dll,D +sRffCommon.dll,DsGccProxy.dll,DsRffProxy.dll,

    If your goal is to have a list of dlls associated with each exe, then you should split each line on commas first. The resulting list of strings you can push onto an array:

    my @dllarray = map { chomp; [ split /,/ ] } @exeDllLines; # iterate over the collected data: for ( @dllarray ) { my( $exe, @dlls ) = @$_; print "$exe uses the following DLLs:\n"; print "$\t$_\n" for @dlls; }

    However, a more robust solution would use a hash:

    my %exeDll; for ( @exeDllLines ) { chomp; my @a = grep /\S/, split /,/; # split on comma; filter out emp +ty fields my @dlls = grep /\.dll$/, @a; # get list of dll files for my $exe ( grep /\.exe$/, @a ) { @{$exeDll{$exe}}{@dlls} = () # OR: $exeDll{$exe}{$_}++ for @dlls; } } # then you can iterate over the collected data: for my $exe ( sort keys %exeDll ) { print "$exe uses the following DLLs:\n"; for my $dll ( sort keys %{ $exeDll{$exe} } ) { print "\t$dll\n"; } }
    We're building the house of the future together.
Re: noob regexpression question
by ikegami (Patriarch) on Nov 07, 2005 at 16:41 UTC

    Although not a *compile* error, you should replace m/exe/ and m/dll/ with m/\.exe$/i and m/\.dll$/i.

    By the way, the following is equivalent (minus the prints) to your code:

    chomp(@exeDllLines); my @dllarray = grep { /\.(?:dll|exe)$/i } @exeDllLines;
    or the more memory-efficient
    chomp(@exeDllLines); my @dllarray; foreach (@exeDllLines) { push @dllarray, $_ if /\.(?:dll|exe)$/i; }

    Update: Oops, not quite. I didn't see the square brackets around DLLs.