如何使用当前文本行中的关键字来搜索Perl中已读取文本的前一行?

时间:2012-09-04 14:34:58

标签: perl text-parsing

我从Perl开始,并在while循环中逐行解析一些文本,但无法找到有关此特定问题的帮助。我想使用当前文本行中先前读取的文本行的信息。

我的代码如下:

while(<data>){

    my $message = substr $_, 0, 1;

    if ($message eq 'A'){

        my $order_ref  = substr $_,  1, 9;
        my $order_book = substr $_, 20, 6;

        push @add_orders, $_;
        print add_order_file "$order_ref,$order_book\n";
    }
    if ($message eq 'X'){

        my $order_ref = substr $_, 1, 9;
        #now I would like to use order_ref to look up order_book from a previous line of text 
        # where the message is equal to A, 
        my $order_book = LOOKED UP VALUE FROM PREVIOUS TEXT;

        push @add_orders, $_;
        print add_order_file "$order_ref,$order_book\n";
    }
}

“A”消息总是在“X”消息之前,所以我确定如果我看到一个带有order_ref编号的X条目,我会向后滚动并找到相关的A消息,我可以在其中提取order_book变量。我意识到这将涉及某种类型的regexp,但我不知道如何使Perl仅搜索前一行。谢谢!

编辑:我应该对此更加清楚。 “A”消息位于“X”消息之前,但它们都可以具有不同的order_ref,因此数据如下所示:

A order_ref1, order_book1
A order_ref2,order_book2
A order_ref3,order_book1
X order_ref2 
X order_ref1

对于X订单,我想使用order_ref2和order_ref1查找order_book。

2 个答案:

答案 0 :(得分:5)

重新定义整个问题后,需要一个新的答案。

您需要将order_ref存储在哈希中,以便以后查找。需要在while循环之外声明此变量。

请注意,我更改了substr次调用中的数字以匹配您的示例输入。如果您共享有关如何构造输入行的一些信息,则可能有更好的方法来提取不同的值。使用substr假定固定宽度类型数据。

use strict;
use warnings;

my %order_book;  # your lookup hash
my @add_orders;
while (<DATA>) {
    chomp;
    my $message = substr $_, 0, 1;

    if ($message eq 'A' or $message eq 'X') {

        my $order_ref = substr $_, 2, 10;
        if ($message eq 'A') {

            $order_book{$order_ref} = substr $_, 13;
        }
        push @add_orders, $_;
        print "$order_ref,$order_book{$order_ref}\n";
    }
}

__DATA__
A order_ref1,order_book1
A order_ref2,order_book2
A order_ref3,order_book1
X order_ref2 
X order_ref1
X order_ref3

输出:

order_ref1,order_book1
order_ref2,order_book2
order_ref3,order_book1
order_ref2,order_book2
order_ref1,order_book1
order_ref3,order_book1

答案 1 :(得分:0)

TLP的答案已经是正确的。以下是对您的代码的一些建议:

use strict; use warnings;
my @add_orders;
my $last_order_book;
while (my $line = <DATA>) {
  my $message = substr $line, 0, 1;

  if ( $message eq "A" ) {
    my $order_ref  = substr $line, 1,  9;
    my $order_book = $last_order_book = substr $line, 20, 6;

    push( @add_orders, $line );
    print "$order_ref,$order_book\n";
  }
  elsif ( $message eq "Q" ) {
    # Stuff happening ...
  }
  elsif ( $message eq "X" ) {
    my $order_ref = substr $line, 1, 9;

    my $order_book = $last_order_book;

    push( @add_orders, $line );
    print "$order_ref,$order_book\n";
  }
}

__DATA__
A123456789012345678901234567890
XLine XLine XLine XLine XABCDEF

我在代码中改变了一些东西。

首先,让我们回答你的问题:如果你不想使用你拥有的那个,你可以添加一个范围在块外的变量来存储你的$order_book在循环内。我把它命名为$last_order_book。它会记住"A"部分中最后看到的值。请注意,您可以通过将它们链接为my $foo = my $bar = "baz"来为多个变量赋值。

现在给我的建议:

  • 始终use strictuse warnings。我不知道你是否这样做,但我会说以防万一。
  • 您经常使用$_。我相信如果你必须经常明确地使用它,那么你实际上应该给它一个名字并使用它。它可以帮助您解决以后发生的事情。
  • 每一行只能有一种$message,所以拥有多个if {}结构是没有意义的。相反,使用if {} elsif {}并按每种线路出现的次数对它们进行排序。这将节省时间,因为它一旦找到其中一个条件就停止执行整个if - 构造。如果你正在处理大量数据,这很有用,但总是这样做并不会有害。为了更清楚,我添加了一个$message eq "Q"案例。