Reinen Text minen

Reinen Text minen

(Originaltitel: grep in Bezug auf Absätze, nicht Zeilen)

Diese Frage ist motiviert durch fzf, wodurch ich eine bestimmte Datei in meinem riesigen Dateisystem finden kannunscharf und inkrementell, bietet eine sehr sehr schnelle Suche (siehe jede Menge süße Gifs in diesemArtikel).

Ich habe vor, ähnliche Dinge mit meinen Notizen zu machen. Ich habe eine Menge flüchtiger Notizen, Tagebücher, Memos usw. im Klartextformat. FürLesbarkeit, jede Zeile enthält nicht mehr als 72 Zeichen. Dies macht es schwierig, nach meiner Notiz zu suchen, basierend auf meinem naiven Wissen über vorhandene Suchwerkzeuge wie grep, ripgrep..

Jetzt können Sie anzeigen (mehr/weniger) Kontext um ein übereinstimmendes Muster herum, aber das ist nicht, wonach ich frage. Hier füge ich ein Beispiel ein, um es genauer zu machen.

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)

Angenommen, ich habe diese Notiz vor einem halben Jahr gemacht und wusste, dass sie irgendwo in meinem Dateisystem ist. Wie üblich können wir die genauen Worte nicht wiedergeben, aberWir erinnern uns an den Kontext! grepWenn ich Texte wie personality, clear thoughtoder victimüber mein Dateisystem kopiere, bekomme ich wahrscheinlichzuviele relevante Dinge, die ich wirklich eingrenzen muss.

Es sollte ein Tool geben (ob vorhanden oder nicht), das bei der Suche nach solchen Texten hilft.Unsere alten Notizen (im Klartext) werden viel wertvoller sein. Gibt es eine Möglichkeit, dies mit unserem guten alten Freund grepund seinen Verwandten zu tun? Oder gibt es andere Möglichkeiten, die funktionieren würden? Auch jede Meinung ist herzlich willkommen.

Antwort1

Lassen Sie uns den (Such-)Prozess in kleinere Teile aufteilen.

Zuerst müssen wir eine Liste der Dateien abrufen, in denen Sie suchen möchten, z. B. im aktuellen Verzeichnis ( .) alle Dateien mit der Erweiterung txt ( -name "*.txt"), bei denen es sich definitiv um Dateien handelt ( -type f):

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

Dieses Ergebnis kann als Eingabe verwendet werden, um innerhalb dieser Dateien grepzu suchen something. Es gibt Zeilennummer und Dateiname in die Ausgabe ein und ignoriert dabei die Groß-/Kleinschreibung ( -nHi). +Am Ende wird sichergestellt, dass alle Dateien in einer Ausführung (nicht eine auf einmal) durchsucht werden:

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

Wenn die Dateianzahl zu groß ist (> $ARG_MAX), sollten Sie ersetzen+mit \;.

Die Ausgabe des vorherigen Befehls sieht ungefähr so ​​aus:

./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).

Wenn Sie diese Zeilen also aufteilen, :erhalten Sie drei Komponenten: Dateiname, Zeilennummer, in der die Übereinstimmung gefunden wurde, und Zeile selbst.

Wenn Sie diese Informationen nun für jede übereinstimmende Datei speichern, können Sie nach den nächsten Begriffen suchen und die Übereinstimmungsdistanz summieren, um Dateien zu finden, bei denen die gesuchten Begriffe am nächsten liegen.

Wenn Sie in Ihrem Beispieltext nach Ihren 3 Begriffen ( personality, clear thought, victim) suchen, erhalten Sie die entsprechenden Zeilennummern 1, 5 und 2. Die Distanz für diese Datei beträgt also (vom ersten Begriff ausgehend)

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

Sie können die Dateien dann danach sortieren, ob sie alle Begriffe enthalten und in der Datei am nächsten liegen.

Natürlich ist das nicht das ganze Bild, manche Dateien enthalten zum Beispiel denselben Begriff mehrmals und dieser Algorithmus muss einige Entscheidungen zur Berechnung der Distanzen treffen, aber ich denke, das Obige ist ein guter Anfang.

Antwort2

Ein einfacher Perl-Einzeiler kann die Aufgabe erledigen. Der folgende Befehl gibt den Dateinamen gefolgt von „gefunden“ aus, wenn alle Schlüsselwörter (also personalityund clear thoughtund victim) in der Datei vorhanden sind.

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

Ausgabe:

file.txt: found

Erläuterung:

-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

Wenn Sie in allen txt-Dateien suchen möchten, verwenden Sieperl ...... *.txt

verwandte Informationen