0

我有一个程序可以将它运行的周期数打印到日志文件中。我想检索日志文件中的最后一个值以找出运行的总循环数。我正在使用以下代码:

my @cycles = $log =~ /\s+(\d+)\s+Cycles/gsm;
$run{cycles} = $cycles[-1] if @cycles;

是否有一个存储最后匹配值的 perl 特殊变量,以便我可以使用它而不是在数组中收集循环?

4

5 回答 5

1

您可以使用否定的前瞻断言:

($run{cycles}) = $log =~ /\s+(\d+)\s+Cycles(?!.*\s+\d+\s+Cycles)/gsm;

意思是“找到一个数字序列,前面是空格,后面是空格和文字Cycles,后面没有另一个空格、数字、空格和文字的序列Cycles”。

于 2013-03-14T17:51:22.397 回答
1

我认为这就是你想要的:

my @cycles = $log =~ /\s+(\d+)\s+Cycles/gsm;
$run{cycles} = $+ if @cycles;

请注意,正如 squiguy 所说,$1应该也可以解决问题(至少它对我有用)。

最后,如果您真的不需要将所有循环保存在数组中,而只需要最后一个值,您可以这样做:

($run{cycles}) = $log =~ /.+\s(\d+)\s+Cycles/s;
于 2013-03-14T18:26:52.267 回答
1

我不建议将整个日志文件读入内存,但是如果没有更多关于你在做什么的信息,我就无法编写适当的逐行解决方案。

带有修饰符的正则表达式模式在下一次匹配时/g停止,因此您只需要一个循环。while

请注意,使用/mor/s修饰符没有任何意义,因为它们所做的只是修改元字符^$的功能.。由于您没有使用这些,它们没有任何效果。

while ( $log =~ /\s+(\d+)\s+Cycles/g ) {
    $run{cycles} = $1;
}
于 2013-03-14T18:32:37.367 回答
0

你的问题不完整。您没有显示将日志文件放入 $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 量相同,但内存使用量要低得多。

你原来的程序是:

  1. 打开日志文件,抓取整个日志文件的内容,关闭 lofile
  2. 查找所有记录的周期
  3. 使用记录的最后一个周期(如果有)

这个程序是:

  1. 打开日志文件
  2. 一次读取一行日志文件
    • 记住上次看到的循环
  3. 关闭日志文件
  4. 使用上次看到的循环,如果有的话
于 2013-03-14T18:27:37.997 回答
0

为什么不直接使用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;
}

应该快很多。

于 2013-03-14T21:16:57.840 回答