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

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

Hello monks... I have kind of a question...I have this code that pushes lines to an array if a certain condition is true:
my (@search); my $query = "perl"; open(FILE, "myfile.txt"); flock(FILE, 1); my @lines = <FILE>; close(FILE); foreach my $lines(@lines){ chomp($lines); push(@search, $lines) if grep { /$query/ } $lines; }
This checks each line to see if it has the word perl in it...if it has it pushes the whole line to the @search array. My problem is that sometimes the text doesnt have the word..so I need to know if @search has any content... How can I do this? I already tried
if(@search){ print "Hey...I found something\n" }
But it doesnt seem to work... Any help is gladly accepted... Thanks

Replies are listed 'Best First'.
Re: Checking Arrays
by grep (Monsignor) on Aug 18, 2002 at 21:57 UTC

    You are recreating the functionality of grep.

    Where you are using grep, that should be just a regexp or (even better) index. But back to the point, grep works on a list and returns a list of matches

    #!/usr/bin/perl -w use strict; my @lines = ( 'this is line one', 'this is line TWO', 'this is line three', 'this is line four perl', 'this is line fiveperl', 'perl' ); my @search = grep { index($_,'perl')+1 } @lines; # my @search = grep {/perl/} @lines; # # if you don't want line five use /\bperl\b/; print "TRUE\n" if (@search); foreach (@search) { print "$_\n"; }

    If you do use a $var to populate your regexp please use quotemeta

    As for your other question 'if (@array)' will return true if there are any elements in the array (even if the only element is 0 or undef)

    UPDATE: BTW here is the benchmark on the re vs. index solution

    Benchmark: timing 100000 iterations of index, re... index: 4 wallclock secs ( 3.54 usr + 0.00 sys = 3.54 CPU) @ 28 +248.59/s (n=100000) re: 7 wallclock secs ( 6.98 usr + 0.00 sys = 6.98 CPU) @ 14 +326.65/s (n=100000)


    grep
    Mynd you, mønk bites Kan be pretti nasti...
Re: Checking Arrays
by adrianh (Chancellor) on Aug 18, 2002 at 23:56 UTC

    Weeeelllll...

    First I add strict & warnings since I'm paranoid.

    I also notice that I'm not checking the return values of the open, flock and close, which could cause problems, so we sprinkle a few die statements in appropriate places.

    I'm using a fixed constant in the "flock", which is naughty, so we'll load up Fcntl to get the proper constants in - I assume that I want a shared lock since that's what "1" normally is.

    (I am, of course, also assuming that whatever is potentially fiddling with these files is also being nice and using flock properly - the wonders of co-operative locking :-)

    Since regexes are pretty darn fast, it almost certainly doesn't make sense to read in the whole file into memory for the sake of shortening the time of the lock. So we change the loop so we examine each line as we read it in.

    Hmmm... "$lines" should probably be called "$line" since it's only a single line.

    In this:

    push(@search, $line) if grep { /$query/ } $line;

    As grep says, you're misunderstanding what grep does. Since we're just looking at a single line we can just use a simple match like this

    push @search, $line if $line =~ m/$query/;

    Note: this assumes that $query might be a regex. If you want it to be interpreted literally you would need to do:

    push @search, $line if $line =~ m/\Q$query/;

    (ammendum... actually you should really use index since the regex match would be overkill)

    Put all of this together and we get

    use strict; use warnings; use Fcntl ':flock'; my @search; my $query = "perl"; open(FILE, "/Users/adrianh/Desktop/myfile.txt") or die; flock(FILE, LOCK_SH) or die; foreach my $line (<FILE>) { chomp($line); push @search, $line if $line =~ m/\Q$query/; } close(FILE) or die;

    Your test of "@search" should work as you expect... for example:

    print "We found...\n", @search ? join("\n", @search) : "nowt\n";

    so I suspect some other problem with the script run caused it not to fire.

    Maybe you should consider some tests :-) :-)

    Hope this helps.

Re: Checking Arrays
by jmcnamara (Monsignor) on Aug 19, 2002 at 14:17 UTC

    A lot of the other replies show how you can process the data after you've read it. But perhaps it might be better to process that data as you read it. Like this:
    #!/usr/bin/perl -w use strict; my @search; my $query = qr/perl/; open FILE, "file" or die "Error message here: $!"; while (<FILE>) { push @search, $_ if /$query/; } chomp @search; # If required close(FILE);

    Also, the qr// operator is useful for pre-compliling a regular expression that will be used as a variable. See perlop for details.

    --
    John.

Re: Checking Arrays
by Anonymous Monk on Aug 19, 2002 at 03:03 UTC
    Use $#search to find the size of the array
      Use $#search to find the size of the array

      No, it will not return the number of elements in an array!!!

      $#search will tell you the last index position.

      So a one element array 'my @arr = qw/ one /;'
      $#arr will return 0 which is false, not what the poster wanted



      grep
      Mynd you, mønk bites Kan be pretti nasti...
      Use $#search to find the size of the array.

      Slightly OT seeing as that's not what the poster was asking. Anyhoo, that's not how you find the size of an array. You'd want to do something like this:
      my $count = @search;
      Update: Useless use of scalar alert, cheers Abigail-II!

      -- vek --
        Useless use of scalar alert!
        my $count = @search;
        will do fine.

        Abigail