使用Perl打印多行

时间:2016-03-01 01:18:04

标签: regex perl slurp

此代码从我拥有的文本文件中获取关键字“fun”,然后在关键字之前和之后打印20个字符。但是,我还希望它打印前两行和接下来的两行,我不知道该怎么做。我不确定用这个更改代码是否更容易,或者只是一次读取整个文件。

{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;                
 }

2 个答案:

答案 0 :(得分:0)

您的代码似乎

  1. &#39;承诺&#39; 而非$searchword的每一边取20个字符;
  2. 有一个无与伦比的&#39; {&#39;在开始时;
  3. 不打印任何文件内容,除了我们无法检查的&amp; write_excel;和
  4. 存在逻辑问题,如果找到$searchword,则$goodline无条件设置为&#39; 1&#39;然后测试看它的&#39; 1&#39;最后重置为&#39; 0&#39;
  5. 把它放在一边,关于是否读取整个文件的问题取决于你的具体情况 - 你要搜索的文件有多大,你的机器有足够的内存;机器是共享资源等等。我认为你可以在整个档案中读到,因为这是我经历中更常见的立场(那些不同意的人请记住(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...。每当使用正则表达式时 - 特别是如果你试图在多行上匹配东西,那么使用&#34;扩展模式&#34; (在最后的&#39; /&#39;之后加上&#39; x)以允许正则表达式中的无关紧要的空格。这样可以实现更清晰的布局。

    我还将行的定义分开,以增加清晰度,其中包含0个,1个或多个非换行符\N*,后跟新行\n。但是,如果您的目标位于第一行,第二行,倒数第二行或最后一行,我认为您仍然需要该信息,因此可选地匹配所请求的前后行对。 $line?

    请注意,正则表达式是迂腐的,并且不可避免地存在细节和细节。这会影响成功匹配与不想要的匹配的定义 - 即。不要期望在所有情况下都能做到完全你想要的东西。期待你必须尝试和调整一些东西。

答案 1 :(得分: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节。