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

Regex perl-如何根据行的位置从文件中提取行,regex,perl,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 ope

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

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之后文件中出现的Let say FOO的OCcrure


非常感谢您的帮助

在perl中有几种方法可以做到这一点,具体取决于您想要完成的任务。如果我没看错的话,你是在寻找FOO和BAR的时间戳,大概是想提取一个delta

关键问题是——FOO和BAR是否完全匹配

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

#!/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
或者你正在做什么-逐行迭代:

#!/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
此解决方案使用“范围”操作符查找第一条条形线,然后是其后的第一条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

我认为您的示例中的/bar/是一个输入错误,因为您的大量数据是bar,并且您的正则表达式不区分大小写?谢谢,没有想到定义的关键字!试一试,看看这是否有效。在标量上下文中,它不应该被称为触发器操作符吗?@paveljurca:不,因为当范围只有一个时,触发器是两个音节。同样的原因使得hash比可笑的七音节关联数组更可取。因为它对一系列的值返回true。好的,这是合理的。那么,我将继续使用range:
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;
   ...
 }
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