Mineração de texto simples

Mineração de texto simples

(título original: grep em termos de parágrafos, não de linhas)

Esta questão é motivada por fzf, o que me permite localizar um determinado arquivo em meu enorme sistema de arquivosconfusa e incrementalmente, proporcionando uma experiência de pesquisa muito rápida (veja vários gifs fofos nesteartigo).

O que tenho em mente é fazer coisas semelhantes em minhas anotações. Tenho um monte de notas fugazes, diários, memorandos... etc, em formato de texto simples. Paralegibilidade, cada linha não contém mais de 72 caracteres. Isso torna minha nota difícil de ser pesquisada, com base em meu conhecimento ingênuo sobre ferramentas de pesquisa existentes como grep, ripgrep..

Agora você pode mostrar (mais/menos) contexto em torno de um padrão correspondente, mas não é isso que estou pedindo. Aqui incluo um exemplo para torná-lo mais preciso.

1  Victim mentality is an acquired personality trait in which a person
2  tends to recognize or consider themselves as a victim of the negative
3  actions of others, and to behave as if this were the case in the face
4  of contrary evidence of such circumstances. Victim mentality depends
5  on clear thought processes and attribution.
6
7  (from wikipedia: Victim mentality)

Digamos que eu tenha feito essa anotação há meio ano e sabia que ela estava em algum lugar do meu sistema de arquivos. Como sempre, não podemos recitar as palavras exatas, masnos lembramos do contexto! grepler textos como personality, clear thoughtou victimno meu sistema de arquivos provavelmente me darátambémmuitas coisas relevantes para eu realmente restringir.

Deveria haver uma ferramenta (existente ou não) que ajudasse a pesquisar textos como este.Nossas notas antigas (em texto simples) serão muito mais valiosas. Existe uma maneira de fazer isso com nosso bom e velho amigo grepe seus parentes? Ou existem outras maneiras que funcionariam? Qualquer opinião também é muito apreciada.

Responder1

Vamos dividir o processo (de pesquisa) em partes menores.

Primeiro precisamos obter uma lista de arquivos que você deseja pesquisar, como no diretório atual ( .) todos os arquivos com extensão txt ( -name "*.txt") que certamente são arquivos ( -type f):

find . -name "*.txt" -type f

Este resultado é possível usar como entrada para grepencontrar somethingdentro desses arquivos, incluindo o número da linha e o nome do arquivo na saída, ignorando case ( -nHi), +no final garante que todos os arquivos sejam recebidos em uma execução (não um de cada vez):

find . -name "*.txt" -type f -exec grep -nHi 'something' {} +

Se a contagem de arquivos for muito grande (> $ARG_MAX), você deverá substituir+com \;.

A saída do comando anterior é algo como:

./some/dir/somewhere/songs.txt:128:But had me believing it was always something that I'd done
./some/dir/somewhere/songs.txt:883:Was never something I pursued
./some/dir/somewhere/songs.txt:2905:I know something about love 
./some/dir/somewhere/songs_other.txt:11780:will come across something like this:  F (Dshape).

Portanto, se você dividir essas linhas, :obterá 3 componentes: nome do arquivo, número da linha onde a correspondência foi encontrada e a própria linha.

Agora, se você mantiver essas informações para cada arquivo correspondente, poderá pesquisar os próximos termos e somar a distância correspondente para encontrar os arquivos, onde os termos pesquisados ​​estão mais próximos.

Para o seu texto de exemplo, se você pesquisar seus 3 termos ( personality, clear thought, victim), você obterá números de linha correspondentes como 1, 5 e 2, então a distância para este arquivo é (originária do primeiro termo)

abs(1-5) + abs(1-2) = 5 

Assim, você pode classificar os arquivos de acordo com todos os termos e tê-los mais próximos nesse arquivo.

Claro, isso não é tudo, por exemplo, alguns arquivos contêm o mesmo termo várias vezes e esse algoritmo precisa tomar algumas decisões sobre como calcular distâncias, mas acho que acima é algo para começar.

Responder2

Um simples one-liner Perl pode fazer o trabalho. A seguir será impresso o nome do arquivo seguido de "encontrado" se todas as palavras-chave (ou seja, personalitye clear thoughte victimestiverem presentes no arquivo).

perl -0777 -ane 'print "$ARGV: found\n" if /^(?=.*personality)(?=.*clear thought)(?=.*victim)/s' file.txt 

Saída:

file.txt: found

Explicação:

-0777       # slurp mode
-ane        # read the file ans execute the following
print "$ARGV: found\n"      # print,$ARGV contains the current filename
if                          # if
  /                         # regex delimiter
    ^                       # begining of file
      (?=.*personality)     # positive lookahead, make sure we have "personality"
      (?=.*clear thought)   # positive lookahead, make sure we have "clear thought"
      (?=.*victim)          # positive lookahead, make sure we have "victim"
  /s                        # regex delimiter, s = dot matches newline

Se você quiser pesquisar em todos os arquivos txt, useperl ...... *.txt

informação relacionada