2009-11-25 55 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