grep は複数の正規表現を検索し、発生回数を計算します。

grep は複数の正規表現を検索し、発生回数を計算します。

複数の正規表現を検索し、各正規表現の一致数を数える必要があるファイルがあるとします。

したがって、次のパターンを組み合わせることはできません。

grep -Po '{regex_1}|{regex_2}|...|{regex_n}' file | wc -l

...各正規表現の発生回数が必要だからです。

明らかにすることができます:

occurences[i]=$(grep -Po "${regex[i]}" file | wc -l)

...しかし、残念ながら、見つかったファイルは非常に大きくなる可能性があり(> 1 GB)、確認する必要があるパターンが多く(数千の範囲)、同じファイルを複数回読み取る必要があるため、プロセスは非常に遅くなります。

これをすばやく実行する方法はありますか?

答え1

おそらくawk最速のシェルツールです。あなたは試すことができます:

awk "/$regex1/ { ++r1 }
     /$regex2/ { ++r2 }"'
     END { print "regex1:",r1 "\nregex2:",r2 }' <infile

perlもちろん、あなたの質問のように正規表現を使用する必要がある場合は、perlそれが唯一の答えです。ただし、基本式の代わりにawk拡張式(たとえば)を使用します。grep -E

答え2

私が考えることができる最も速い解決策は柔軟。テストされていないスケルトンは次のとおりです。

%{
  int count[1000];
%}
%%

regex0  {count[0]++; }
regex1  {count[1]++; }
...
.|\n    {}

%%
int main(){
   yylex();
   // printf the counts;
}

flexはオートマタを最適化し、高速Cコードを生成するのに非常に効果的です。

正規表現が変更されたら、再コンパイルする必要があります。

編集する:どのようなソリューションを実装して試してみると、時間を見ているのも面白いでしょう。

答え3

Pythonがオプションの場合は、まず次のことができます。メモリマップファイルを見つけて、次を使用して増分正規表現検索を実行します。名前付きグループパターンの発生回数を計算します。このソリューションは、大容量ファイルサイズに耐えることができます。

from collections import Counter
import re, mmap, contextlib
c = Counter()
with open('data_file', 'r+') as f:
    with contextlib.closing(mmap.mmap(f.fileno(), 0)) as data:
            for m in re.finditer(r'(?P<pat1>regex1)|(?P<pat2>regex2)|(?P<pat3>regex3)',data):
                    c.update(k for (k, v) in m.groupdict().iteritems() if v)

print c.most_common()
[('pat3', 3), ('pat1', 2), ('pat2', 2)]

関連情報