perl - 如何根据文件的位置从文件中提取行

时间:2015-08-31 09:46:09

标签: regex perl

我正在处理文本文件以提取包含时间戳的行,然后对这些时间戳执行计算。该行包含一个时间戳,后跟一条消息,我正在执行正则表达式以提取。

TIME | MESSAGE
20:48:27.159 | FOO
20:48:47.353 | BAR
20:48:49.227 | SPAM
20:48:52.192 | FOO

下面是我在文件

上执行的正则表达式的sudo代码
... .... ... 


open (my $FH, "<", $file) or die "Cannot open <$file>: $!";
for my $line (<$FH>) {
    if ($line =~ /bar/) {
        my $ts1 = ExtractTimestamp($line);
    } elsif ($line =~ /FOO/) {
        my $ts2 = ExtractTimestamp($line);
    }
}
my $diff = $ts2 - $ts1;

这里的问题是正则表达式找到第一次出现的行并提取它,这给我留下了负时间戳。我想知道在perl中是否有任何模块或任何技术我可以在BAR之后提取文件中出现的FOO事件?

感谢您的帮助!

3 个答案:

答案 0 :(得分:5)

此解决方案使用范围运算符查找第一个BAR行,后面跟着第一个FOO行。如果记录中的时间是范围中的第一行或最后一行,则将记录中的时间推送到数组@ts

use strict;
use warnings;

my @ts;
while ( <DATA> ) {
    next unless my $state = /BAR/ .. /FOO/;
    push @ts, /([\d:.]+)/ if $state == 1 or $state =~ /E/;
}

print join(' ... ', @ts), "\n";

__DATA__
TIME | MESSAGE
20:48:27.159 | FOO
20:48:47.353 | BAR
20:48:49.227 | SPAM
20:48:52.192 | FOO

输出

20:48:47.353 ... 20:48:52.192

答案 1 :(得分:2)

open (my $FH, "<", $file) or die "Cannot open <$file>: $!";
# define $ts1 and $ts2 OUTSIDE "for" loop
my( $ts1, $ts2);
for my $line (<$FH>) {
    if ($line =~ /bar/) {
        $ts1 = ExtractTimestamp($line);
    } 
    # ignore FOO before first BAR sets $ts1
    elsif ( defined($ts1) and $line =~ /FOO/) { 
        $ts2 = ExtractTimestamp($line);
        # stop searching after first FOO and "BAR after FOO" pair
        last;
    }
}
# if both FOO and "BAR after FOO" has set their variables
if( defined($ts1) and defined($ts2)) {
   my $diff = $ts2 - $ts1;
   ...
 }

答案 2 :(得分:0)

有几种方法可以在perl中执行此操作,具体取决于您要完成的任务。如果我正确地读你,你正在寻找FOOBAR时间戳,并且可能试图提取delta?

关键问题是 - FOOBAR完全匹配吗?

我的意思是,你可以通过多行正则表达式来实现:

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

local $/;

my ( $bar, $foo )  =  <DATA> =~ m/^(\d\S+) \| BAR.*?(\d\S+) \| FOO$/ms;
print "BAR: $bar\nFOO: $foo\n";

__DATA__
TIME | MESSAGE
20:48:27.159 | FOO
20:48:47.353 | BAR
20:48:49.227 | SPAM
20:48:52.192 | FOO

这将匹配配对的'BAR'和'FOO'的第一个实例。 (如果在正则表达式上使用g标志,则可以多次捕获)。

或者 - 您可以将记录分隔符设置为FOO

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

local $/ = "FOO\n"; 

while ( <DATA> ) {

   my ( $foo ) = m/(\S+) \| FOO/;
   my ( $bar ) = m/(\S+) \| BAR/;
   print "$foo $bar\n";

}

__DATA__
TIME | MESSAGE
20:48:27.159 | FOO
20:48:47.353 | BAR
20:48:49.227 | SPAM
20:48:52.192 | FOO

或者你在做什么 - 逐行迭代:

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

my $last_bar;
while (<DATA>) {

    if (m/^(\d\S+) \| BAR/) {
        $last_bar = $1;
    }
    if ( my ($foo) = m/^(\d\S+) \| FOO/ ) {
        if ($last_bar) {
            print "$foo $last_bar\n";
        }
        else {
            print "Unmatched:\n";
            print;
        }
        $last_bar = undef;
    }
}

__DATA__
TIME | MESSAGE
20:48:27.159 | FOO
20:48:47.353 | BAR
20:48:49.227 | SPAM
20:48:52.192 | FOO