Reputation: 13172
I have a piece of code which opens up a file and parses it. This text document has a redundant structure and has multiple entries. I need to peek ahead within my loop to see if there is a new entry, if there is, I will be able to parse all of the data my program extracts. Let me first show my implementation so far
use strict;
my $doc = open(my $fileHandler, "<", "test.txt");
while(my $line = <$fileHandler>) {
## right here I want to look at the next line to see if
## $line =~ m/>/ where > denotes a new entry
}
Upvotes: 4
Views: 12740
Reputation: 11
I just used the Tie::File code in #5 for great justice. My in file had a hostname and the next line was either a hostname or the host's crit level. If there was a crit level, I made a line with the hostname & crit for output to a CSV; if there was no crit assigned, I assigned it 0.
(I had to split the lines because the line was name:servername or critlevel:99, along with cleaning up leading/trailing spaces)
for my $linenumber (0..$#file) {
#print "$file[$linenumber]\n";
if ($file[$linenumber] =~/name/) {
($crap,$server) = split(/\:/,$file[$linenumber],2);
$server =~ s/^\s+|\s+$//g;
#print "$server\n";
if ($file[$linenumber+1] =~/server/ && $linenumber <=$#file) {
($crap,$crit) = split(/\:/,$file[$linenumber+1],2);
$crit =~ s/^\s+|\s+$//g;
#print "$crit\n";
}
else { $crit = "0"; }
$outstr = "$server,$crit\n";
print $outstr;
print OUTFILE $outstr;
}
}
Upvotes: 0
Reputation: 67910
A nice way to handle these problems is using Tie::File
, which allows you to treat a file like an array, without the performance penalty of actually loading the file into memory. It is also a core module since perl v5.7.3.
use Tie::File;
tie my @file, 'Tie::File', "test.txt" or die $!;
for my $linenr (0 .. $#file) { # loop over line numbers
if ($file[$linenr] =~ /foo/) { # this is the current line
if ($file[$linenr + 1] =~ /^>/ && # this is the next line
$linenr <= $#file) { # don't go past end of file
# do stuff
}
}
}
untie @file; # all done
Upvotes: 5
Reputation: 5801
Try handling the iteration yourself:
my $line = <$fileHandler>;
while(1) { # keep looping until I say so
my $nextLine = <$fileHandler>;
if ($line =~ m/>/ || !defined $nextLine) {
### Do the stuff
}
### Do any other stuff;
last unless defined $nextLine;
$line = $nextLine;
}
I added the extra check in the if statement under the assumption that you will also want to process what you have when you reach the end of the file.
Alternatively, as suggested by friedo, if the file can fit into memory, you can load the whole thing into an array at once:
my @lines = <$fileHandler>;
for (my $i = 0; $i <= $#lines; $i++) {
if ($i == $#lines || $lines[$i+1] =~ />/) {
### Do the stuff
}
}
This is more flexible in that you can access any arbitrary line of the file, in any order, but as mentioned the file does have to be small enough to fit into memory.
Upvotes: 9