我有一个ASCII日志的文件的一些内容,我谨提取物。我从来没有时间来学习Perl正确的,但我想,这是一个很好的工具,用于这项任务。

该文件的结构是这样的:

... 
... some garbage 
... 
... garbage START
what i want is 
on different
lines 
END 
... 
... more garbage ...
next one START 
more stuff I want, again
spread 
through 
multiple lines 
END 
...
more garbage

因此,我在寻找一种方法来提取的线之间的每 STARTEND 符串。我怎么可以这样做?

迄今为止,我只找到一些例子如何打印一行的 START 串,或其他文件的项目,有些有关的用什么我要找的。

有帮助吗?

解决方案

你想要触发器操作符(更好地称为范围操作符) ..

#!/usr/bin/env perl
use strict;
use warnings;

while (<>) {
  if (/START/../END/) {
    next if /START/ || /END/;
    print;
  }
}

将对 print 的调用替换为您实际想做的事情(例如,将线条推入数组,编辑,格式化,无论如何)。我是 next - 超过实际拥有 START END 的行,但您可能不需要这种行为。有关此运算符和其他运算符的讨论,请参见本文。有用的Perl特殊变量。

其他提示

perlfaq6 如何在不同行上的两个模式之间拉出线?


你可以使用Perl有点奇特的运算符(在perlop中记录):

perl -ne 'print if /START/ .. /END/' file1 file2 ...

如果你想要文字而不是线条,你可以使用

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

但是如果您想要嵌套出现START到END,那么您将遇到本节中有关匹配平衡文本的问题中描述的问题。

这是使用..的另一个例子:

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}

我怎么可以抢多行之后一个匹配线在Perl?

怎么是那一个吗?在这一个,结束串$^,你可以改变它向最终串。

我也是一个新手,但解决方案有提供相当多的方法...让我知道更具体的是什么是你想要的,不同于上述的链接。

while (<>) {
    chomp;      # strip record separator
    if(/END/) { $f=0;}
    if (/START/) {
        s/.*START//g;
        $f=1;
    }
    print <*>

尝试下次编写一些代码

."\n" if $f; }

尝试下次编写一些代码

在Telemachus的回复之后,事情开始倾泻而出。这就是我正在研究的解决方案。

  1. 我正在尝试提取由两个字符串分隔的行(一个,一行以“CINFILE =”;一行,其中一行包含单个“#”)在单独的行中,不包括分隔符线。我可以使用Telemachus的解决方案。
  2. 第一行有一个我想删除的空格。我也包括它。
  3. 我也试图将每个行集提取到单独的文件中。
  4. 这适用于我,虽然代码可以归类为丑陋;这是因为我现在几乎是Perl的新手。无论如何这里是:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    my $start='CINFILE=
    
    

    我希望它也有益于其他人。 欢呼声。

    ; my $stop='^#

    我希望它也有益于其他人。 欢呼声。

    ; my $filename; my $output; my $counter=1; my $found=0; while (<>) { if (/$start/../$stop/) { $filename=sprintf("boletim_%06d.log",$counter); open($output,'>>'.$filename) or die $!; next if /$start/ || /$stop/; if($found == 0) { print $output (split(/ /))[1]; } else { print $output

    在Telemachus的回复之后,事情开始倾泻而出。这就是我正在研究的解决方案。

    1. 我正在尝试提取由两个字符串分隔的行(一个,一行以“CINFILE =”;一行,其中一行包含单个“#”)在单独的行中,不包括分隔符线。我可以使用Telemachus的解决方案。
    2. 第一行有一个我想删除的空格。我也包括它。
    3. 我也试图将每个行集提取到单独的文件中。
    4. 这适用于我,虽然代码可以归类为丑陋;这是因为我现在几乎是Perl的新手。无论如何这里是:

      <*>

      我希望它也有益于其他人。 欢呼声。

      ; } $found=1; } else { if($found == 1) { close($output); $counter++; $found=0; } } }

    我希望它也有益于其他人。 欢呼声。

来自“虚拟新手”并不太糟糕。你能做的一件事就是把“$ found = 1”放在上面。在“if($ found == 0)”的内部阻止,以便您每次在$ start和$ stop之间不执行该任务。

在我看来,另一件有点难看的事情是,每次进入$ start / $ stop-block时都会打开相同的文件处理程序。

这表明了解决方法:

#!/usr/bin/perl

use strict;
use warnings;

my $start='CINFILE=;
my $stop='^#;
my $filename;
my $output;
my $counter=1;
my $found=0;

while (<>) {

    # Find block of lines to extract                                                           
    if( /$start/../$stop/ ) {

        # Start of block                                                                       
        if( /$start/ ) {
            $filename=sprintf("boletim_%06d.log",$counter);
            open($output,'>>'.$filename) or die $!;
        }
        # End of block                                                                         
        elsif ( /$end/ ) {
            close($output);
            $counter++;
            $found = 0;
        }
        # Middle of block                                                                      
        else{
            if($found == 0) {
                print $output (split(/ /))[1];
                $found=1;
            }
            else {
                print $output 

来自“虚拟新手”并不太糟糕。你能做的一件事就是把“$ found = 1”放在上面。在“if($ found == 0)”的内部阻止,以便您每次在$ start和$ stop之间不执行该任务。

在我看来,另一件有点难看的事情是,每次进入$ start / $ stop-block时都会打开相同的文件处理程序。

这表明了解决方法:

<*>; } } } # Find block of lines to extract }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top