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

Hello I have been trying to search for a pattern in an array, I have managed to search through each line and find the pattern and then print a 'found pattern' statement however currently the script prints 'did not find pattern' if it does not find it on a line. I only want it to print success/failure text if it finds pattern somewhere in the array and not whether it finds it in a line ( if that makes sense). I will be searching for a few different patterns in the array and will have to only print a "found patterns" statement or "did not find patterns" statement for the complete search.... any ideas how to optimize this code?
foreach (@commands_run){ if($_ =~m/clock/) { print "\n Test -- found pattern -- \n";} else {print "\n Test -- did not find pattern -- \n";} }

Replies are listed 'Best First'.
Re: searching through array for multiple patterns
by Bloodnok (Vicar) on Jul 16, 2009 at 10:36 UTC
    Why not just keep it simple:
    print qq/found\n/ if grep /clock/, @commands_run;
    A user level that continues to overstate my experience :-))
Re: searching through array for multiple patterns
by dsheroh (Monsignor) on Jul 16, 2009 at 10:42 UTC
    If I understand the question correctly, you have a pattern and you want to determine whether or not it appears in your array as a whole rather than checking each element of the array individually, right?

    grep can do that:

    if (grep(/clock/, @commands_run)) { print "\n Test -- found pattern -- \n"; } else { print "\n Test -- did not find pattern -- \n"; }

    While this is the easiest way to do this, you may want to benchmark it against si_lence and skirnir's solution to see which is faster for your dataset. grep is more highly optimized in its searching, but it will continue on to find all matches in the array rather than aborting after finding the first.

Re: searching through array for multiple patterns
by si_lence (Deacon) on Jul 16, 2009 at 07:56 UTC
    I'm not sure I understand your question completely. If you want to print your 'found / not found' once, i.e. whether the pattern is present or absent in the array you could either join the array into a string an match the string (just make sure you don't create a match by joining the elements of the array) or have a flag that indicates a match and print your message after looping over your array.
    use strict; use warnings; my @commands_run = qw(first second clock fourth); #join all elements of the array my $all_commands = join '#', @commands_run; if ($all_commands =~m/clock/) { print "\n Test -- found pattern -- \n"; } else { print "\n Test -- did not find pattern -- \n"; } #use a flag to indicate a match my $found = 0; foreach (@commands_run) { if($_ =~m/clock/) { $found++; } } $found ? print "\n Test -- found pattern -- \n" : print "\n Test -- did not find pattern -- \n";
    cheers

    si_lence

      in the latter case you don't need to continue the loop after you found a match. Thus I'd do it this way:
      #use a flag to indicate a match my $found = 0; foreach (@commands_run) { if($_ =~m/clock/) { $found++; last; # we have a match, exit loop } } $found ? print "\n Test -- found pattern -- \n" : print "\n Test -- did not find pattern -- \n";
      of course in this case you can omit the $found ? print ...: print ..; part:
      foreach (@commands_run) { if($_ =~m/clock/) { print "found pattern\n"; last; # we have a match, exit loop } }
      You are perfectly right with your remarks about optimizing the loop.
      Good catch!

      cheers, si_lence

Re: searching through array for multiple patterns
by cdarke (Prior) on Jul 16, 2009 at 07:51 UTC
    You code is searching through the array @commands_run, I am puzzled by your reference to "line".

    if it finds pattern somewhere in the array and not whether it finds it in a line ( if that makes sense)

    Sorry, but its does not make sense to me. Even if your array contains multi-line records, if it is on a line then it is in the array, you are not looking anywhere else. Maybe you need to post more code?
      Hi Presently the code searches through each line looking for the pattern and prints success statement if it finds in a line and failure statement if it does not find it (for each line). I want it to either print success or failure statement once for the searching of the whole array. thanks
        I'm with you, in that case just set a flag if the element is found, then break out of the loop at once (no point in continuing to search):
        my $found = 0; foreach (@commands_run){ if($_ =~ m/clock/) { $found = 1; last; } } if ($found) { print "\n Test -- found pattern -- \n" } else { print "\n Test -- did not find pattern -- \n" }

        maybe somthing like

        if(index("@commands_run",'clock') >= 0) { # string 'clock' found somewhere in array }

        -- 
        Ronald Fischer <ynnor@mm.st>
Re: searching through array for multiple patterns
by toolic (Bishop) on Jul 16, 2009 at 17:21 UTC
    Another potential solution (if I understand the problem) is to use the any function from List::MoreUtils. You should benchmark it against other solutions for your actual data to determine which is most optimal.
    use strict; use warnings; use List::MoreUtils qw(any); my @commands = ( 'chicks with bricks come', 'chicks with blocks come', 'chicks with bricks and blocks and clocks come' ); if (any { /clock/ } @commands) { print "Found pattern\n"; } else { print "Did not find pattern\n"; } __END__ Found pattern
Re: searching through array for multiple patterns
by biohisham (Priest) on Jul 16, 2009 at 11:59 UTC
    you are talking of matching multiple lines, to be frank, I am new to Perl too and I am not sure if I heard this right "an array of multiple lines" , what I understand is it does not embed new line characters in it and that its length is a one line that spans multiple screen lines, but probably you wanna make your array into a string as many wise monks have suggested and then extend the search pattern to go through multiple lines, to be wholesome, and soon as a match occurs it exits the conditional loop....so I will add to the suggested ideas this loop here too in which a string with new line characters iis being matched and not an array.
    #!/usr/local/bin/perl use strict; use warnings; my $match=0; my $string = "do you know my name is Simon\n I have a clock on my wal +l"; while(){ if($string=~ /\bclock\b/s){ $match++; last; }else{last;} } $match ? print "Found Pattern!\n":print "did not find pattern!\n";
    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind