1

此代码从我拥有的文本文件中获取关键字“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;                
 }
4

2 回答 2

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节中。

于 2016-03-01T03:26:55.280 回答
0

你的代码似乎

  1. 不要在“承诺”的每一侧取 20 个字符$searchword
  2. 开头有一个不匹配的'{';
  3. 不打印除 &write_excel 之外的任何我们无法检查的文件内容;和
  4. 存在逻辑问题,如果$searchword找到,$goodline无条件设置为“1”,然后测试是否为“1”,最后重置为“0”

撇开这一点不谈,是否读取整个文件的问题取决于您的情况——您要搜索的文件有多大,您的机器是否有足够的内存?机器是共享资源等等。我假设您可以阅读整个文件,因为这是我的经验中更常见的立场(那些不同意的人请记住(a)我承认它值得商榷;并且(b)它非常依赖于只有 OP 知道的情况)

鉴于此,有几种方法可以读取整个文件,但共识似乎是使用 module 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?

请注意,正则表达式是迂腐的,并且不可避免地存在影响成功匹配与不需要匹配的定义的“细节” - 即。不要指望这在所有情况下都能完全满足您的要求。预计您将不得不进行一些实验和调整。

于 2016-03-01T02:49:30.617 回答