如何在Perl中的匹配行之后抓取多行?

时间:2009-06-24 20:04:55

标签: perl

我正在逐行解析Perl中的一个大文件(以\ n结尾),但当我到达某个关键字时,说“TARGET”,我需要抓住TARGET和下一个完全关联的所有行空行。

所以,给定文件的一部分:

第1行 第2行 3号线 第4行目标
5号线抓住这条线 6号线抓住这条线 \ n

它应该成为:
第4行目标
5号线抓住这条线 第6行抓住这一行

我遇到麻烦的原因是我已经逐行浏览了这个文件;如何在解析过程中途改变我划分的内容?

9 个答案:

答案 0 :(得分:23)

你想要这样的东西:

my @grabbed;
while (<FILE>) {
    if (/TARGET/) {
        push @grabbed, $_;
        while (<FILE>) {
            last if /^$/;
            push @grabbed, $_;
        }
    }
}

答案 1 :(得分:14)

range operator适用于此类任务:

$ cat try
#! /usr/bin/perl

while (<DATA>) {
  print if /\btarget\b/i .. /^\s*$/
}

__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Nope
Line 7 Target
Linu 8 Yep

Nope again

$ ./try
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Line 7 Target
Linu 8 Yep

答案 2 :(得分:10)

简短回答:perl中的行分隔符为$/,因此当您点击TARGET时,可以将$/设置为"\n\n",读取下一个“行”,然后将其设置回到“\ n”...etvoilà!

现在更长的一个:如果你使用English模块(它为Perl的所有魔术变量提供合理的名称,那么$/被称为$RS$INPUT_RECORD_SEPARATOR如果您使用IO::Handle,则IO::Handle->input_record_separator( "\n\n")将有效。

如果您将此作为更大代码的一部分,请不要忘记本地化(在适当的范围内使用local $/;)或将$/设置为原始代码价值"\n"

答案 3 :(得分:4)

perlfaq6回答How can I pull out lines between two patterns that are themselves on different lines?


你可以使用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 $.
}

答案 4 :(得分:2)

while(<FILE>)
{
    if (/target/i)
    {
        $buffer .= $_;
        while(<FILE>)
        {
            $buffer .= $_;
            last if /^\n$/;
        }
    }
}

答案 5 :(得分:1)

use strict;
use warnings;

my $inside = 0;
my $data = '';
while (<DATA>) {
    $inside = 1 if /Target/;
    last if /^$/ and $inside;
    $data .= $_ if $inside;
}

print '[' . $data . ']';

__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Next Line

编辑以按照下面的注释修复退出条件。

答案 6 :(得分:0)

如果您不介意丑陋的自动生成代码,并假设您只想要TARGET和下一个空行之间的行,并希望删除所有其他行,则可以使用此输出命令:

s2p -ne '/TARGET/,/^$/p'

(是的,这是暗示这个问题通常在sed中更容易解决。:-P)

答案 7 :(得分:0)

如果你只想要一个循环(修改Dave Hinton的代码):

my @grabbed;
my $grabbing = 0;
while (<FILE>) {
    if (/TARGET/ ) {
       $grabbing = 1;
    } elsif( /^$/ ) {
       $grabbing = 0;
    }
    if ($grabbing) {
        push @grabbed, @_;
    }
}

答案 8 :(得分:0)

String deli_time = shared_preference.getString("delivery_time", "");
List<String> timeList1 = Arrays.asList(deli_time.split(" ")); 
String time_value = timeList1.get(1).trim()+" "+timeList1.get(2).trim();
Date dateObj = sdf2.parse(time_value);
time_value = sdf1.format(dateObj);
Date dateObj1 = sdf3.parse(timeList1.get(0));
dayOfTheWeek = sdf.format(dateObj1);
String time = "";
time = ZainbowDatabase.getInstance(MyBasket.this).getTimeForDay(mall_id, t1_vendor_id, dayOfTheWeek, 2);

if(time.length() > 0 && !time.equalsIgnoreCase("")){
    String time1, time2 = "";
    if(time.contains(",")){
        List<String> timeList = Arrays.asList(time.split(","));
        time1 = timeList.get(0);
        time2 = timeList.get(1);
    }else
        time1 = time;

    boolean check_time = AppConstant.checkTime(time1, time2, time_value);