in reply to Loop through array or filehandle

So if I understand correctly, the data in the new format will all reside in one array, with a single line per element. If so, have a review of this example code. I simply check the reference type with ref, and act accordingly.

My test input file (file.txt) contains:

this is line 1 in fh blah this is line 2 in fh

Code:

use warnings; use strict; my $search = 'blah'; open my $fh, '<', 'file.txt' or die $!; my @lines = ( "this is line 1 of aref\n", "this is line 2 of aref blah\n", ); parse_line($fh); parse_line(\@lines); sub parse_line { my $arg = shift; if (ref $arg eq 'GLOB'){ # file handle while (<$arg>){ if (/$search/){ print; last; } } } elsif (ref $arg eq 'ARRAY'){ # aref for (@$arg){ if (/$search/){ print "$_\n"; last; } } } else { print "unsupported type...\n"; exit; } }

Output:

this is line 1 in fh blah this is line 2 of aref blah

Replies are listed 'Best First'.
Re^2: Loop through array or filehandle
by markdibley (Sexton) on Sep 29, 2016 at 16:07 UTC

    This is what I was getting at, but was wondering if there was a way of treating both sets of data within the same loop.

    Is there any way of using the filehandle as an array (without loading the whole file into an array)?

      I do not know if this is any better for your purpose, but you could create an iterator so that the loop uses the iterator and does not care where the data comes from (the iterator handles that part)

      Just a quick example:

      use warnings; use strict; open my $fh, '<', 'file.txt' or die $!; my @lines = ( "this is line 1; foo \n", "this is line 2: bar \n", "this is line 3: foobar \n", ); sub create_iter { my $arg = shift; if (ref $arg eq 'GLOB') { return sub {<$arg>}; } elsif (ref $arg eq 'ARRAY') { my $index = 0; return sub {$arg->[$index++]} } else { die "Unknown type\n"} } print "PRINTING FROM FH\n"; parse_line($fh); print "\n\nPRINTING FROM ARRAY\n"; parse_line(\@lines); sub parse_line { my $arg = shift; my $iter = create_iter($arg); while (my $val = $iter->()) { print $val if $val =~ /foo/; } }
      This prints out this:
      PRINTING FROM FH this is line 1; foo this is line 3: foobar this is line 4; foobaz PRINTING FROM ARRAY this is line 1; foo this is line 3: foobar

        Thanks again. I think you have come up with the simplest way to do this, although I modified the code slightly (below - doesn't run but is a simplified example of what I was doing). Originally I was wondering if there was a built-in technique that I was missing, but it appears not.

        Thanks again

        #!/usr/bin/perl -ws use strict; open my $fh, '<', 'file.txt' or die $!; my @lines = ( "this is line 1; foo \n", "this is line 2: bar \n", "this is line 3: foobar \n", ); print "PRINTING FROM FH\n"; working_routine($fh); print "\n\nPRINTING FROM ARRAY\n"; working_routine(\@lines); sub create_iter { my $arg = shift; if (ref $arg eq 'GLOB') { return <$arg>; } elsif (ref $arg eq 'ARRAY') { return shift @$arg; } else { die "Unknown type\n"} } sub working_routine{ my ($data) = @_; my $flag = 0; while(my $line = create_iter($data)){ if($line =~ /matches something/){ next; } elsif($line =~ /matches something else/ and ! $flag){ create_iter($data); my $newline = create_iter($data); dosomethingto($newline); } elsif($line =~ /gotcha/ && $flag){ morework($line); } else{ next; } } }
        Interesting! Thanks. I get it.

        Interestingly, data from an HTTP::Request, when split by \n into an array, only loops to the first empty line and then the while loop stops. If the data from the request is written to a file then the while loop works as expected.

        The only work around I can find at the moment is to

        $data =~ s/^$/ /gsm

        Not ideal, but better than working out why an empty line from an HTTP::Request GET signals a termination of a while() loop.

      Is there any way of using the filehandle as an array (without loading the whole file into an array)?

      Tie::File

        Thanks! Does what I wanted (although originally I was looking to see if there was some clever way of using filehandles built into the perl core - should have explained that better).