我有一段代码可以打开一个文件并解析它。该文本文档具有冗余结构并且具有多个条目。我需要在循环中向前查看是否有新条目,如果有,我将能够解析程序提取的所有数据。让我首先展示到目前为止我的实现
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
}
尝试自己处理迭代:
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;
}
我在 if 语句中添加了额外的检查,假设您还想在到达文件末尾时处理您所拥有的内容。
或者,按照 Friedo 的建议,如果文件可以放入内存,您可以立即将整个文件加载到数组中:
my @lines = <$fileHandler>;
for (my $i = 0; $i <= $#lines; $i++) {
if ($i == $#lines || $lines[$i+1] =~ />/) {
### Do the stuff
}
}
这更灵活,因为您可以按任何顺序访问文件的任意行,但正如前面提到的,文件必须足够小才能适合内存。
Tie::File
,它允许您将文件视为数组,而不会因实际将文件加载到内存中而造成性能损失。它也是从 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
我只是为了正义而使用了 #5 中的 Tie::File 代码。我的文件有一个主机名,下一行是主机名或主机的暴击级别。如果存在暴击级别,我会用主机名和暴击创建一行以输出到 CSV;如果没有指定暴击,我就指定为0。
(我必须拆分行,因为该行是 name:servername 或 critlevel:99,并清理前导/尾随空格)
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;
}
}