grep para múltiplos regexes e conta o número de ocorrências

5

Digamos que eu tenha um arquivo e vários regexes precisem ser pesquisados nele e o número de correspondências de cada regex deve ser contado.

Assim, não posso combinar os padrões:

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

... como o número de ocorrências para cada regex é necessário.

Eu obviamente poderia:

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

... mas, infelizmente, os arquivos encontrados podem ser bem grandes (> 1 GB) e há muitos padrões (no intervalo de milhares) a serem verificados, tornando o processo bastante lento, como várias leituras do arquivo. mesmo arquivo estaria envolvido.

Existe uma maneira de fazer isso de maneira rápida?

    
por user2064000 31.12.2014 / 11:47

3 respostas

5

Provavelmente awk seria a ferramenta shell mais rápida aqui. Você poderia tentar:

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

É claro que se você precisar usar perl expressões regulares como a sua pergunta, realmente perl é a única resposta. No entanto, awk usa expressões estendidas (como grep -E ) em oposição às básicas.

    
por 31.12.2014 / 12:12
4

A solução mais rápida que consigo pensar é flex . A seguir, um esqueleto não testado:

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

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

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

flex faz um ótimo trabalho na otimização dos autômatos e gera um código C rápido.

Você tem que recompilar se os regexs mudarem ...

EDITAR : Se você implementar e tentar qualquer uma das soluções, seria interessante ver os horários.

    
por 31.12.2014 / 13:56
0

Caso o Python seja uma opção, você pode primeiro mapear a memória no arquivo e executar uma pesquisa de regex incremental sobre Aproveitando os grupos nomeados para contar as ocorrências de padrões. Esta solução é tolerante a tamanhos grandes de arquivos

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)]
    
por 31.12.2014 / 16:41