搜索文件,找到匹配项后,将其存储,然后打印出4行以上,3行以下

时间:2012-05-22 22:47:00

标签: perl

我有一个简单的搜索脚本,可以在目录和用户之间进行用户输入和搜索。文件,只列出它找到的文件。我想要做的是能够找到匹配,在它上面抓4行,在它下面3行并打印它。所以,让我说我有。

somefile.html

"a;lskdj a;sdkjfa;klsjdf a aa;ksjd a;kjaf ;;jk;kj asdfjjasdjjfajsd  jdjd
jdjajsdf<blah></blah> ok ok okasdfa stes test tes tes test test<br>

blah blah blah ok, I vouch for the sincerity of my post all day long.
Even though I can sometimes be a little crass.

I would only know the blue moon of pandora if I saw it. I heard tales of long ago 
times in which .. blah blah

<some html>whatever some number 76854</some html>

running thru files of grass etc.. ===> more info
whatever more "

并且假设我想找到“76854”它会打印或存储在数组中,这样我就可以打印在dirs / files中找到的所有匹配项。

*Match found:*

**I would only know the blue moon of pandora if I saw it. I heard tales of long ago 
times in which .. blah blah
<some html>whatever whatever</some html>
running thru files of grass etc.. ===> more info
whatever more**


**********************************

这样的事情。到目前为止,我已经通过打印出找到匹配项的文件来工作:

if ($args->{'keyword'}){
    if($keyword =~ /^\d+$/){
    print "Your Results are as Follows:\n";
        find( sub
            {
                local $/;
                return if ($_ =~ /^\./);
                return unless ($_ =~ /\.html$/i);
                stat $File::Find::name;
                return if -d; #is the current file a director?
                return unless -r; # is the file readable?
                open(FILE, "< $File::Find::name") or return;
                my $string = <FILE>;
                close (FILE);
                print "$keyword\n";
                if(grep /$keyword/, $string){
                    push(@resultholder, $File::Find::name);
                }else{
                   return;
                }
             },'/app/docs/');
    print "Results: @resultholder\n";
    }else{
        print "\n\n ERROR\n";
        print "*************************************\n\n";
        print "Seems Your Entry was in the wrong format \n\n";
        print "*************************************\n\n";
    }
exit;
}

3 个答案:

答案 0 :(得分:3)

perl是先决条件吗?使用grep这很容易,你可以告诉它在匹配前后打印N行。

grep <search-term> file.txt -B <# of lines before> -A <# of lines after>

请忽略你是否真的想要使用perl,只是抛出一个替代品。

答案 1 :(得分:3)

您使用的是Windows还是Linux?

如果你在Linux上,你的脚本最好用以下代码替换:

grep -r -l 'search_string' path_to_search_directory

它会列出包含search_string的所有文件。要获得前面的4行上下文和行匹配后的3行,您需要运行:

grep -r -B 4 -A 3 'search_string' path_to_search_directory

如果由于某种原因你不能或不想使用grep,你需要改进你的脚本。

首先,使用这种结构,您只能读取文件中的第一个字符串:

my $string = <FILE>;

其次,你最好避免将所有文件都读到内存中,因为你可以遇到几个Gb文件。甚至读一个字符串到内存,因为你可以遇到真正的大字符串。将其替换为顺序读取到一些小缓冲区。

最后一个,在你需要从找到的匹配中执行反向读取之前得到4行和3行之后(在匹配之前寻找到buffer_size的位置,读取该块并检查是否有足够的换行符)在它)。

答案 2 :(得分:2)

因此,您需要存储至少8行,并在第5行与您的模式匹配时输出这8行。用于从数组前面删除元素的shift运算符和用于在列表末尾添加元素的push运算符可能会有所帮助。

find( sub {
    ...  # but don't set $\

    open( FILE, '<', $File::Find::name) or return;
    my @buffer = () x 8;
    while (<FILE>) {
        shift @buffer;
        push @buffer, $_;
        if ($buffer[4] =~ /\Q$keyword\E/) {
            print "--- Found in $File::Find::name ---\n";
            print @buffer;
            # return?
        }
    }
    close FILE;

    # handle the case where the keyword is in the last ~4 lines of the file.
    while (@buffer > 5) {
        shift @buffer;
        if ($buffer[4] =~ /\Q$keyword\E/) {
            print "--- Found in $File::Find::name ---\n";
            print @buffer;
        }
    }
} );