web-dev-qa-db-ja.com

複数の正規表現のgrep、および発生数のカウント

たとえば、ファイルがあり、そのファイルで複数の正規表現を検索し、各正規表現の一致数をカウントする必要があるとします。

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

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

...各正規表現の出現回数が必要なため。

私は明らかにできました:

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

...しかし残念ながら、検出されたファイルは非常に大きく(> 1 GB)、チェックするパターンが多数(数千の範囲)あるため、同じファイルを複数回読み取るとプロセスが非常に遅くなります。関与。

これを迅速に行う方法はありますか?

6
user2064000

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

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

もちろん、質問のようにPerl正規表現を使用する必要がある場合は、実際にはPerlが唯一の答えです。ただし、awkは、基本的な式ではなく、拡張式(grep -Eなど)を使用します。

5
Graeme

私が考えることができる最速の解決策はflexです。以下は、テストされていないスケルトンです。

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

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

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

flexは、オートマトンの最適化において非常に優れた仕事をし、高速なCコードを生成します。

Regexが変更された場合は、再コンパイルする必要があります...

[〜#〜] edit [〜#〜]:いずれかのソリューションを実装して試してみると、時代を見るのが面白いでしょう。

4
JJoao

Pythonがオプションの場合、最初に memory-map ファイルを実行してから、 名前付きグループ)を利用して、ファイルに対して増分正規表現検索を実行できます。 パターンの発生をカウントします。このソリューションは大きなファイルサイズに耐性があります

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)]
1
iruvar