Tutorial :Perl - the fastest way to read a range of lines from a file into a variable



Question:

Given a start and end line number, what's the fastest way to read a range of lines from a file into a variable?


Solution:1

The following will load all desired lines of a file into an array variable. It will stop reading the input file as soon as the end line number is reached:

use strict;   use warnings;    my $start = 3;  my $end   = 6;  my @lines;  while (<>) {      last if $. > $end;      push @lines, $_ if $. >= $start;  }  


Solution:2

Use the range operator .. (also known as the flip-flop operator), which offers the following syntactic sugar:

If either operand of scalar .. is a constant expression, that operand is considered true if it is equal (==) to the current input line number (the $. variable).

If you plan to do this for multiple files via <>, be sure to close the implicit ARGV filehandle as described in the perlfunc documentation for the eof operator. (This resets the line count in $..)

The program below collects in the variable $lines lines 3 through 5 of all files named on the command line and prints them at the end.

#! /usr/bin/perl    use warnings;  use strict;    my $lines;  while (<>) {    $lines .= $_ if 3 .. 5;  }  continue {    close ARGV if eof;  }    print $lines;  

Sample run:

$ ./prog.pl prog.pl prog.c main.hs  use warnings;  use strict;      int main(void)  {  import Data.Function (on)  import Data.List (sortBy)  --import Data.Ord (comparing)


Solution:3

You can use flip-flop operators

while(<>) {  if (($. == 3) .. ($. == 7)) {      push @result, $_;  }  


Solution:4

Reading line by line isn't going to be optimal. Fortunately someone has done the hardwork already :) use Tie::File; it present the file as an array. http://perldoc.perl.org/Tie/File.html


Solution:5

# cat x.pl    #!/usr/bin/perl    my @lines;    my $start = 2;    my $end = 4;    my $i = 0;    for( $i=0; $i<$start; $i++ )    {         scalar(<STDIN>);    }       for( ; $i<=$end; $i++ )    {         push @lines, scalar(<STDIN>);    }       print @lines;  # cat xxx     1       2       3       4       5     # cat xxx | ./x.pl    3       4       5     #     

Otherwise, you're reading a lot of extra lines at the end you don't need to. As it is, the print @lines may be copying memory, so iterating the print while reading the second for-loop might be a better idea. But if you need to "store it" in a variable in perl, then you may not be able to get around it.

Update:

You could do it in one loop with a "continue if $. < $start" but you need to make sure to reset "$." manually on eof() if you're iterating over or <>.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »