2009-11-25 54 views
1

您好我想搜索的东西在文件中匹配看起来与此类似:省略或排除正则表达式Perl脚本

Start Cycle 
report 1 
report 2 
report 3 
report 4 
End Cycle 

....推移和..

我要搜索“开始循环”,然后拉出报告1,并从中报告3。我的正则表达式看起来像这样

(Start Cycle .*\n)(.*\n)(.*\n)(.*\n) 

上述正则表达式选择开始周期,下三行..但我想从我的结果中省略第三行。那可能吗?或者任何更简单的perl脚本都可以完成? 我期待像结果:

Start Cycle 
report 1 
report 3 

回答

5

下面的代码打印Start CycleEnd Cycle之间的奇数行:

foreach (<$filehandle>) { 
    if (/Start Cycle/ .. /End Cycle/) { 
     print if /report (\d+)/ and $1 % 2; 
    } 
} 
1

正则表达式填充$ 1,$ 2,$ 24和$ 32,每对括号的内容。

所以,如果你只是看看$ 1,$ 2和$ 4的内容,你有你想要的。

或者,您可以从第三行中删除括号。

你的正则表达式应该是这个样子

/Start Cycle\n(.+)\n.+\n(.+)\n.+\nEnd Cycle/g 

的/ G允许你反复评估正则表达式,总是每次都获得下一场比赛。

2

你可以找到的开始和结束市场上赢得然后通过线分割背景之间的文本。下面是例子:

my $text = <<TEXT; 
Start Cycle 
report 1 
report 2 
report 3 
report 4 
End Cycle 
TEXT 

## find text between all start/end pairs 
while ($text =~ m/^Start Cycle$(.*?)^End Cycle$/msg) { 
    my $reports_text = $1; 
    ## remove leading spaces 
    $reports_text =~ s/^\s+//; 
    ## split text by newlines 
    my @report_parts = split(/\r?\n/m, $reports_text); 
} 
1

如果你想离开所有周围的代码相同,但停止捕获的第三件事,你可以简单地删除导致该行要捕获的括号:

(Start Cycle .*\n)(.*\n).*\n(.*\n) 
2

也许是一种疯狂的方式:改变Perl对输入记录的理解。

$/ = "End Cycle\n"; 
print((/(.+\n)/g)[0,1,3]) while <$file_handle>; 
0

更新:我最初没有注意到,这只是@FM's answer在一个稍微更稳健和更长的形式。

#!/usr/bin/perl 

use strict; use warnings; 

{ 
    local $/ = "End Cycle\n"; 
    while (my $block = <DATA>) { 
     last unless my ($heading) = $block =~ /^(Start Cycle\n)/g; 
     print $heading, ($block =~ /([^\n]+\n)/g)[1, 3]; 
    } 
} 

__DATA__ 
Start Cycle 
report 1 
report 2 
report 3 
report 4 
End Cycle 

输出:

 
Start Cycle 
report 1 
report 3 
0
while (<>) { 
    if (/Start Cycle/) { 
     print $_; 
     $_ = <>; 
     print $_; 
     $_ = <>; $_ = <>; 
     print $_; 
    } 
} 
1

我把OP的问题,作为一个Perl的锻炼和用下面的代码上来。它只是为了学习目的而写的。如果有任何可疑的情况,请纠正我。

while(<>) { 
    if(/Start Cycle/) { 
     push @block,$_; 
     push @block, scalar<> for 1..3;    
     print @block[0,1,3]; 
     @block=(); 
      } 
     } 

另一个版本(编辑感谢,@ FM):

local $/; 
$_ = <>; 
    @block = (/(Start Cycle\n)(.+\n).+\n(.+\n)/g); 
    print @block; 
+0

看起来不错,迈克 - 在列表环境很好使用数组切片,啜食模式和正则表达式。两个小问题。 (1)在例#1中,如果在循环中添加my @ block作为第一个命令,那么您将正确地确定数组的范围,并可以删除'@block =()'。看到这一些细节:http://stackoverflow.com/questions/845060/what-is-the-difference-between-my-and-our-in-perl/990945#990945。 (2)例#2有点误导,因为你根本不需要循环。如果您删除循环并使用'$ _ = '代替,您的代码将以相同的方式工作并更清楚地表达其行为。 – FMc 2009-11-26 15:15:04

+0

@FM,感谢分享这些想法:)我不知道我的声明可以在这里自然地替换数组空行。感谢指针。而对于第二段代码,我同意,因为slup模式已启用,while循环不是真正的循环。我对这一段声明的理解绝对是错误的。 – Mike 2009-11-27 04:07:52

+0

哇只是看起来像有多种方式在Perl中做到这一点。 :)我仍然是一个n00b – FatDaemon 2009-11-30 18:35:56