【问题标题】:grep lines matching a pattern, and the lines before and after the matchinggrep 匹配模式的行,以及匹配之前和之后的行
【发布时间】:2012-03-06 12:08:25
【问题描述】:

我想对一个文件(大约 200 兆字节)进行模式匹配,然后将匹配行以及每个匹配行之前和之后的任意行数推入一个数组。

sub1,使用 perl grep,耗时 11 秒

sub2,使用unix egrep,1秒

sub6 (ack) 50 秒(如果你不使用 \b、\s 锚等会更快)

从命令行确认需要 15 秒

我对加速 sub1 的建议感兴趣,或者寻找不依赖外部工具的快速 perl 解决方案

perl grep 似乎比 unix 慢很多。

"index" 确实比正则表达式快(但我需要 \b、\s 等)

http://www.perlmonks.org/?node_id=885174

http://www.perlmonks.org/?node_id=957554

谢谢

use 5.014;
use strict;
use warnings;
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
use List::MoreUtils qw(uniq);

open FILE, '<textMatchInAfile.txt' or die;
my $p = '\bsala|che|relazione|di|questo|coso|^qui\$';
my $mR = 1;        #print more rows before - after the matching
my @n  = <FILE>;

&sub1( $p, $mR, @n );    #suggest: insert references
&sub3( $p, $mR );

sub sub1 {               #questa sub usa perl grep
my $p    = $_[0];             #pattern
my $mR   = $_[1];             #more rows
my @n    = @_[ 2 .. $#_ ];    #input File
my $time = [gettimeofday];
my @new = grep { $n[$_] =~ /$p/ } 0 .. $#n;
my @unique =
  map { @n[ $_ - $mR .. $_ + $mR ] } @new[ 0 + $mR .. $#new - $mR];
say "\n" . 'time sub1 perl grep: ' . tv_interval($time);
@unique = uniq(@unique);
say "sub 1 $#unique";
}

sub sub3 {    #unix grep with color and line numbers
my $p   = $_[0];
my $mR  = $_[1];
my $cmd = "grep -n -C $mR";    #with line numbers
$p =~ s/\|/ /g;
$p =~ s/\h+/" -e "/g;
$p = ' -e "' . $p . '" ';
say "cmd ===$cmd=== ss ===$p===";
my @values;
$values[0] = $p;
$values[1] = ( ' ' . 'textMatchInAfile.txt' );    
my $time = [gettimeofday];
my @valori = `$cmd @values` or die "system @values` failed: $?";
say 'sub3 egrep shell: ' . $#valori;
say 'time sub3 tempo trovati con egrep shell ' . tv_interval($time);
my @uniq_list = uniq(@valori);
}

sub sub6 {             #perl ack
my $p  = $_[0];    #pattern
my $mR = $_[1];    #more rows
my @values;
my $time   = [gettimeofday];
my @valori = qx (ack -C $mR "$p" textMatchInAfile.txt)
  or die "system @values` failed: $?";
say 'number of values found with ack' . $#valori;
say 'time sub6 ack' . tv_interval($time);
}
#
#this one takes 11 seconds

 use 5.014;
 use warnings;
 use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);

 my @array;
 my $pattern = '\bsala|che|relazione|di|questo|coso|^qui\$';
 open( my $filehandle, "<textMatchInAfile.txt" );
 my $time = [gettimeofday];
 while (<$filehandle>) {
     if ( $_ =~ /$pattern/ ) {
    push @array;
     }
 }
 say 'time while' . tv_interval($time);

好吧好吧,unix grep 比 perl grep 快一个数量级,我会接受的。

【问题讨论】:

  • 我推荐使用Benchmark 模块。我发现您的代码有点难以阅读,并且很难编写自己的代码,因为我需要一些输入数据的样本。但据我所知,您正在将文件的全部内容加载到数组中。最好做一个while 循环并逐行处理文件。毕竟 Perl 应该几乎与带有管道的 unix 工具一样快编译后,这可能需要一些时间(对于大量输入数据来说微不足道)。
  • 我的输入数据只是普通的文本散文。我发现没有办法与 unix grep 的速度竞争,我想我已经尝试了所有可能的方法
  • 好吧,我尝试用一​​些数据编写自己的子程序来解决这个问题(只是为了好玩),但这是不可能的,因为我绝对无法理解您的代码实际上在做什么。考虑到您的示例潜艇的质量和效率,我很确定您的代码仍有很大的优化空间。但是除非你提供一些数据并描述你真正想用它做什么,否则没人会告诉你。
  • 谢谢,我确定没有太多优化空间,使用 unix grep 的 sub 总是快 10 倍左右,我尝试了很多不同的解决方案。

标签: perl grep


【解决方案1】:

为什么不使用 grep -B 1 -A 1?

这将为您提供所需的确切输出。

grep -B 1 -A 1 -E patter file

问候,

【讨论】:

  • grep 已经包含在原始帖子中,但我更喜欢 perl 解决方案
  • 好吧,我已经看到 unix grep 比 perl grep 快一个数量级,没有任何代码优化可以推翻它。
【解决方案2】:

我对 Unix 的 egrep 和 Perl 的 grep 命令做了一些基本的比较,后者有两种不同的实现。

use Benchmark qw(cmpthese);

my $count = $ARGV[0] || 100;

my $re = "L[aeiou]n*.?[xyz]\\b";

cmpthese($count, {
    unix => sub {
        my $result = `dmesg|egrep '$re'`;

        #print "===unix===\n";
        #print $result;
    },
    perl => sub {
        my @result = grep {$_ =~ m/$re/} split m/\n/, `dmesg`;

        #print "===perl===\n";
        #map {print "$_\n"} @result;
    },
    perl2 => sub {
        open(DMESG, "dmesg|" ) or die "cannot open dmesg pipe!";

        my @result;

        while(<DMESG>) {
            push @result, $_ if m/$re/;
        }

        #print "===perl2===\n";
        #map {print} @result;

        close DMESG;
    },
});

结果:

$ perl grep.pl 1000
        Rate  unix  perl perl2
unix  24.6/s    --  -40%  -44%
perl  41.0/s   67%    --   -6%
perl2 43.6/s   77%    6%    --

那么请解释一下为什么 Perl 的 grep 自然比 Unix 慢 grep

PS 我调整了脚本以在包含 25k 行随机数据和不同 RE 的文件上运行。这种情况和你的情况有点相似。

$ perl tmp/grep.pl 1000
        Rate  unix  perl perl2
unix  3.71/s    --  -32%  -44%
perl  5.50/s   48%    --  -17%
perl2 6.64/s   79%   21%    --

【讨论】:

  • 感谢您的代码,对不起,但速度较慢... my $re = '\bsala|che|relazione|di|questo|coso|^qui\$';按 ENTER 或键入命令继续 Rate perl perl2 unix perl 28.6/s -- -5% -76% perl2 29.9/s 5% -- -75% unix 118/s 312% 293% --
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2021-06-16
  • 2015-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-07
相关资源
最近更新 更多