2011-11-25 42 views
3

我一直在尋找一種解決方案,它允許我搜索數組的行,並且如果進行了字符串匹配,請將該行和前兩行插入數組中。看起來這很容易使用grep命令完成。但是,我無法得到這個工作。這是我的:如何在Perl中模擬'grep -B'功能?

sub ipsearch { 
    my $ip = $_[0]; 
    my @IPVSCONFIG = grep (/\W+virtual\s$ip\s/, @RAWDATA); 
} 

是否可以將「-B 2」語法添加到grep命令?我試過幾種形式這個語法,但我無法得到它的工作:

@IPVSCONFIG = grep -B 2 (/\W+virtual\s$ip\s/, @RAWDATA); 

請讓我知道,如果這甚至有可能和正確的語法應該是什麼。如果您有任何其他建議,請告訴我。

感謝您的幫助!

+0

這都多久,但對於未來的讀者:[相關文章](https://stackoverflow.com/a/44493583/4653379) – zdim

回答

5

關鍵是要找出何處發生匹配的線,然後確定相關指數圍繞:

獲取匹配指數:

my @matchedIndices = grep { $RAWDATA[$_] =~ /\W+virtual\s$ip\s/ } 2 .. $#RAWDATA; 

各地獲取指數:

my @wantedIndices = map { ($_-2 .. $_) } @matchedIndices; 

並採取陣列切片:

my @IPVSCONFIG = @RAWDATA[ @wantedIndices ]; 

乾脆把它在一個使用Schwartzian變換:

my @IPVCONFIG = map { @RAWDATA[$_-2..$_] } 
       grep { $RAWDATA[$_] =~ /\W+virtual\s$ip\s/ } 
       2 .. $#RAWDATA ; 

肯定比傳統的命令行grep -B 2一個多忙的解決方案!

+0

+1看起來不錯。活動扳手:如果0-1行匹配會怎麼樣? – TLP

+0

@TLP:好點!改變了從索引2開始的範圍 – Zaid

+0

這工作得很好!非常感謝您爲每條生產線提供的解決方案和解釋。 – dars33

2

您正在使用名爲grepperldoc -f grep)的perl函數混合使用grep程序/bin/grep。前者需要額外的參數,如-B,後者則不。

3

你的子程序的基本版本。我假設你想要在完成它時返回列表。未經測試。

sub ipsearch { 
    my $ip = shift; 
    my @IPVSCONFIG =(); # no matches should be empty list, not undef 
    my @buffer =()  # to avoid undef warnings 
    for (@RAWDATA) { 
     push @buffer, $_; 
     shift @buffer if @buffer > 3; 
     if (/\W+virtual\s$ip\s/) { 
      push @IPVSCONFIG, @buffer; 
      @buffer =(); 
     } 
    } 
    return @IPVSCONFIG; 
} 
+0

+1不像Zaid的版本 – DVK

+0

@DVK兩次掃描數據實際上,他只掃描一次數據。除非您將'map $ RAWDATA [$ _]'作爲掃描之一。 – TLP

+0

對不起,不完全。我的意思是把原文分解爲@RAWDATA作爲額外的掃描(你的觀點也是一種掃描,但它是O(M),其中M是匹配數)。你的代碼和'@ RAWDATA'一樣可以和'<$filehandle>'一起工作,因此可以很容易地適用於只掃描一次特大文件。扎伊德不能。一個額外的++主要好處是節省內存。 – DVK