我有一个程序可以将它运行的周期数打印到日志文件中。我想检索日志文件中的最后一个值以找出运行的总循环数。我正在使用以下代码:
my @cycles = $log =~ /\s+(\d+)\s+Cycles/gsm;
$run{cycles} = $cycles[-1] if @cycles;
是否有一个存储最后匹配值的 perl 特殊变量,以便我可以使用它而不是在数组中收集循环?
您可以使用否定的前瞻断言:
($run{cycles}) = $log =~ /\s+(\d+)\s+Cycles(?!.*\s+\d+\s+Cycles)/gsm;
意思是“找到一个数字序列,前面是空格,后面是空格和文字Cycles
,后面没有另一个空格、数字、空格和文字的序列Cycles
”。
我认为这就是你想要的:
my @cycles = $log =~ /\s+(\d+)\s+Cycles/gsm;
$run{cycles} = $+ if @cycles;
请注意,正如 squiguy 所说,$1
应该也可以解决问题(至少它对我有用)。
最后,如果您真的不需要将所有循环保存在数组中,而只需要最后一个值,您可以这样做:
($run{cycles}) = $log =~ /.+\s(\d+)\s+Cycles/s;
我不建议将整个日志文件读入内存,但是如果没有更多关于你在做什么的信息,我就无法编写适当的逐行解决方案。
带有修饰符的正则表达式模式在下一次匹配时/g
停止,因此您只需要一个循环。while
请注意,使用/m
or/s
修饰符没有任何意义,因为它们所做的只是修改元字符^
和$
的功能.
。由于您没有使用这些,它们没有任何效果。
while ( $log =~ /\s+(\d+)\s+Cycles/g ) {
$run{cycles} = $1;
}
你的问题不完整。您没有显示将日志文件放入 $log 的代码部分。假设您的日志文件的名称在 $logFile 您的问题是如何改进:
my $log = do { local( @ARGV, $/ ) = $logFile ; <> } ;
my @cycles = $log =~ /\s+(\d+)\s+Cycles/gsm;
$run{cycles} = $cycles[-1] if @cycles;
答案是一次读取一行日志文件:
open my $logFH,'<',$logFile
or die "Could not open $logFile: $!";
my $cycles;
while (my $logLine = <$logFH>) {
($cycles) = $logLine =~ /\s+(\d+)\s+Cycles/;
}
close $logFH;
$run{cycles} = $cycles
if $cycles;
这样,您的程序仅使用 $logFile 中最长行的空间而不是整个文件的空间,以及存储单个循环而不是所有循环的空间。
也就是说,I/O 量相同,但内存使用量要低得多。
你原来的程序是:
这个程序是:
为什么不直接使用File::ReadBackwards
并采用“第一条”匹配线。
$bw = File::ReadBackwards->new( 'log_file' )
or die "can't read 'log_file' $!"
;
while( defined( $log_line = $bw->readline ) ) {
next unless m/\s+(\d+)\s+Cycles/;
print;
last;
}
它应该快很多。