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

Hello, I'm trying to make a routine to catch some expressions from a file. I'm assuming, wrongly, that can only be one in each line... I'm capturing and appending the expressions like this:
sub Grab($filename){ open (file1, "<$filename") or goto cont2; while (<file1>){ my($line) = $_; my ($exp) = $line =~ m/ kepler_ # Required (.+?) # Capture Desired Output (:?\s\(|\(|\s+) # One required - no capture /xi; $expr = "kepler_".$1; if(@Functions =~ /$expr/gi){goto cont1;} if($1 =~ ""){goto cont1;} $n += 1; print $expr."\n"; $value1 = "Exp_".$n; $key1 = $expr; $functions{ $key1 } = $value1; # hash, using variables cont1: } cont2: close file1; } #END GRAB
The problem is that I'm getting duplicated items in the hash. And, that can be more expressions in one line - but probably not... Can anyone help me out here? Kind regards, Kepler

Replies are listed 'Best First'.
Re: Catching expressions from a file
by RonW (Parson) on Jul 25, 2014 at 23:16 UTC

    Two problems stand out to me:

    First:

        if(@Functions =~ /$expr/gi)

    needs to be

        if (grep { /$expr/i } @Functions)

    This will test each member of @Functions with your regular expression. What you wrote will compare the length of @Functions to your expression.

    Also, the g in /gi is not needed.

    So, the whole line is better written as

        next if (grep { /$expr/i } @Functions);

    Then:

        if($1 =~ ""){goto cont1;}

    Two things: The value of $1 is not guaranteed after a failed reg ex match. Also, you have an intervening, unrelated, reg ex match. The following should work:

        next unless ($exp);

    Now, a simple thing:

        open (file1, "<$filename") or goto cont2;

    is better written as

        open (file1, "<$filename") or return;

    If the open fails, there's nothing to close.

    I hope this helps.

      open my $fIn1, '<', $filename or die "Failed to open '$filename': $!\n +";

      is much, much better than the two parameter version of open. If the OP really does want to fail silently then replacing the die with a return as you suggest is fine. Much better though is to leave the die there and have the calling code be explicit about error handling by wrapping the call in an eval and explicitly ignore expected failure modes:

      eval { Grab($filename); return 1; } or do { my $err = $@; return if $err =~ /File not found/; die $err; };

      which gives good information about unexpected error modes and makes it clear that missing files are expected and unimportant (such failures are ignored).

      If you ignore error handling the errors will still happen and manifest themselves in some fashion. But most likely the way they manifest will not be at all obviously related to the underlying error. Spending a little time adding error handling up front almost always pays for itself. Even without writing any code, thinking about failure modes will head off many bugs before they get the chance to bite.

      Perl is the programming world's equivalent of English
Re: Catching expressions from a file
by AnomalousMonk (Archbishop) on Jul 26, 2014 at 01:06 UTC

    In addition to other problems commented upon, I see a couple more: you're using prototypes (improperly); you're not using warnings and strictures (see strict).

    Abandoning the use of prototypes until you understand what they do (and that you should almost never use them) will save you great and needless suffering. Using warnings and strictures will initially cause additional pain, but it will be a healing pain! Addressing the problems that warnings and strictures bring to light will ultimately make your code more robust.

    c:\@Work\Perl\monks>perl -le "use warnings; use strict; ;; my $filename; ;; Grab($filename); ;; $filename = 'too late'; ;; sub Grab($filename){ print qq{filename is '$filename'}; my @ra = (9, 8, 7); print 'it matches!' if @ra =~ m{ 3 }xms; } " Illegal character in prototype for main::Grab : $filename at -e line 1 +. Applying pattern match (m//) to @array will act on scalar(@array) at - +e line 1. main::Grab() called too early to check prototype at -e line 1. Use of uninitialized value $filename in concatenation (.) or string at + -e line 1. filename is '' it matches!
Re: Catching expressions from a file
by Anonymous Monk on Jul 25, 2014 at 21:48 UTC

    The problem is that I'm getting duplicated items in the hash.

    That isn't possible, hashes don't keep duplicates, they're hashes

    Can anyone help me out here?

    Not with the information presented. See Re: String extract 2 ask better questions (code that compiles, clearly stated goals, sample input, wanted output, the output you actually get and explanation of why its wrong)

Re: Catching expressions from a file
by AppleFritter (Vicar) on Jul 25, 2014 at 22:13 UTC
      I'm very sorry - I didnt know the post didnt belong here. Kind regards, Kepler