2

ユーザー入力を取得してディレクトリとファイル全体を検索し、見つかったファイルを一覧表示する単純な検索スクリプトがあります。一致が見つかったときに、その上にある 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」を見つけたいとしましょう。配列に印刷または保存されるため、ディレクトリ/ファイルで見つかったすべての一致を印刷できます。

*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;
}
4

3 に答える 3

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 のファイルに遭遇する可能性があるため、すべてのファイルをメモリに読み込むことは避けたほうがよいでしょう。また、1 つの文字列をメモリに読み込んでも、非常に大きな文字列に遭遇する可能性があります。小さなバッファーへのシーケンシャル読み取りに置き換えます。

そして最後に、見つかった一致から 4 行前と 3 行後に逆読み取りを実行する必要があります (一致する前に buffer_size の位置をシークし、そのブロックを読み取り、十分な改行があるかどうかを確認します)。 .

于 2012-05-22T23:07:37.300 に答える
3

ここでperlは前提条件ですか?これは grep を使えば簡単です。一致の前後に N 行を出力するように指示できます。

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

本当に perl を使用したい場合は無視してください。単に代替手段を捨てるだけです。

于 2012-05-22T22:59:16.520 に答える
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;
        }
    }
} );
于 2012-05-22T23:06:25.983 に答える