2016-03-01 221 views
1

此代碼從我擁有的文本文件中抓取關鍵字'fun',然後打印關鍵字前後的20個字符。但是,我也希望它能打印前兩行和後兩行,我不知道該怎麼做。我不確定是否更容易更改代碼或只是一次讀取整個文件。使用Perl打印多行

{my $inputfile = "file"; 
$searchword = 'fun'; 
open (INPUT, '<', $inputfile) or die "fatal error reading the file \n"; 
while ($line1=<INPUT>) 
{ 
#read in a line of the file 
if ($line1 =~m/$searchword/i) 
{print "searchword found\n"; 
    $keepline = $line1; 
    $goodline =1; 

    $keepline =~/(.{1,20})(fun)(.{1,20})/gi; 

    if ($goodline==1) 
    {&write_excel}; 
$goodline =0;     
} 
+0

它讀起來好像每個「祈願」字的每一邊需要20個字符,無論「$ searchword」設置爲什麼?你能澄清嗎? – Marty

+0

此外,除「searchword found」外,它不會打印任何我們可以看到的內容 - 也就是說''write_excel'會執行某些操作,但是您沒有發佈它的內容。 – Marty

+0

我很抱歉,祈願應該讀「樂趣」。此外,這是一個子例程,寫入excel部分在我的代碼後面。如果這有幫助,我可以發佈一切。 –

回答

0

你的代碼,就是似乎

  1. 以20個字符'承諾'沒有$searchword的每一側;
  2. 有一個無與倫比的'{'在開始;
  3. 不打印任何文件內容除了&我們無法檢查的write_excel;和
  4. 具有如果$searchword被發現,$goodline無條件地設置爲「1」,然後進行測試以查看是否它的「1」和最後復位爲「0」

把的是,除了在一個邏輯問題,關於是否讀取整個文件的問題取決於你的情況,有些內容 - 你要搜索的文件有多大,你的機器是否有足夠的內存,是機器共享資源等。我會假定你可以閱讀整個文件,因爲這是我的經驗中較爲常見的位置(那些不同意請記住(a)我已經承認它有爭議;並且(b)它非常依賴於只有OP知道的情況下)

鑑於此,有幾種方法可以讀取整個文件,但consensus seems to be要與模塊File::Slurp一起使用。給定這些參數,答案是這樣的;

#!/usr/bin/env perl 
use v5.12; 
use File::Slurp; 

my $searchword = 'fun'; 
my $inputfile = "file.txt"; 
my $contents = read_file($inputfile); 

my $line = '\N*\n'; 
if ($contents =~ /(
     $line? 
     $line? 
     \N* $searchword \N* \n? 
     $line? 
     $line? 
    )/x) { 
    say "Found:\n" . $1 ; 
} 
else { 
    say "Not found." 
} 

File::Slurp打印合理的錯誤消息,如果文件不存在(或遇到其他問題),所以我離開了典型的or die...。每當使用正則表達式時 - 尤其是如果您嘗試在多行上匹配內容時,使用「擴展模式」(通過在最後的'/'之後放置'x')可以允許中的空格在正則表達式中不起作用。這使得佈局更清晰。

爲了增加清晰度,我還分離出了一行的定義,其中包含0,1個或更多非換行符字符\N*,後跟一個新行\n。但是,如果您的目標位於第一條,第二條,倒數第二條或最後一條線上,則我認爲您仍然需要這些信息,因此可以選擇匹配請求的前後兩行。 $line?

請注意,正則表達式是迂腐的,並且不可避免地有'細節'影響成功匹配的定義與不需要的匹配 - 即。不要期望這樣做剛好你想在所有情況下。預計你將不得不嘗試一些事情並討論一些事情。

0

我不確定我是否理解你的代碼塊(「承諾」有什麼用途?什麼是&write_excel?),但我可以自己回答你的問題。

首先,這個grep命令可以接受嗎?這是遠遠快和清潔:

grep -i -C2 --color "fun" "file" 

-C NUM標誌告訴grep提供上下文的圍繞每個模式匹配NUM行。很顯然,--color是可選的,但它可以幫助您找到真正漫長的線路上的匹配。

否則,這裏有點的Perl:

#!/usr/bin/perl 

my $searchword = "fun"; 
my $inputfile = "file"; 

my $blue = "\e[1;34m"; # change output color to blue 
my $green = "\e[1;32m"; # change output color to green 
my $nocolor = "\e[0;0m"; # reset output to no color 

my $prev1 = my $prev2 = my $result = ""; 

open (INPUT, '<', $inputfile) or die "fatal error reading the file \n"; 
while(<INPUT>) { 
    if (/$searchword/i) { 
    $result .= $prev2 . $prev1 . $_; # pick up last two lines 
    $prev2 = $prev1 = "";    # prevent reusing last two lines 
    for (1..2) {      # for two more non-matching lines 
     while (<INPUT>) {    # parse them to ensure they don't match 
     $result .= $_;    # pick up this line 
     last unless /$searchword/i; # reset counting if it matched 
     } 
    } 
    } else { 
    $prev2 = $prev1;     # save last line as $prev2 
    $prev1 = $_;      # save current line as $prev1 
    } 
} 
close $inputfile; 

exit 1 unless $result;    # return with failure if without matches 

$result =~       # add colors (okay to remove this line) 
    s/([^\e]{0,20})($searchword)([^\e]{0,20})/$blue$1$green$2$blue$3$nocolor/g; 
print "$result";      # print the result 
print "\n" unless $result =~ /\n\Z/m; # add newline if there wasn't already one 

錯誤:這是假定前兩行,兩行後,實際上是超過20個字符。如果你需要解決這個問題,它會在else節。