TXT-Datei (>15GB) durchsuchen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Hallo,

ich möchte eine große Wordlist (mehrere GB) nach einem Wort durchsuchen lassen und
die Treffer mit der Zeilennummer ausgeben. Außerdem die Wörter in der Zeile davor und danach.

Ich habe als Python-Neuling folgenden Code zusammengeschnibbelt, der sogar funktioniert.
Leider funktioniert es nur bei Wordlists unter einem GB. Bei größeren Wordlist kommt "Memory Error".

Ich habe schon rausgefunden, dass das Problem bei "x = f.readlines()" steckt, da hier die gesamte Datei
eingelesen wird, richtig? In einem Forum habe ich gefunden, dass man lieber mit "for line in f" arbeiten sollte.
Bei der Umsetzung komme ich aber nicht weiter. Kann jemand helfen?

Code: Alles auswählen


import argparse

ap = argparse.ArgumentParser()
ap.add_argument("-outfile", "--outfile", required=True, help="Txt-File")
ap.add_argument("-infile", "--infile", required=True, help="Txt-File")
ap.add_argument("-insearch", "--insearch", required=True, help="Txt-File")
args = vars(ap.parse_args())
outfile = args["outfile"]
infile = args["infile"]
insearch = args["insearch"]

with open(outfile, 'w', errors='ignore', encoding='utf-8') as text_file:
        
    with open(infile,errors='ignore', encoding='utf-8') as f:
            x = f.readlines()
            for num, line in enumerate(x,1):
                if insearch in line:
                
                    text_file.write("Line: " + str(num) + " found: " + line)
                    text_file.write("Line before: " + str(x[num-2]))
                    text_file.write("Line next: " + str(x[num]) + "\n")
                    
text_file.close()
f.close()
          
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Das with-statement sorgt bereits dafür, dass die Datei korrekt geschlossen wird. Das musst du in diesem Fall nicht explizit tun.
.readlines() liest, wie du bereits festgestellt hast, die komplette Datei in den Speicher. Und auch die Lösung, dass man direkt über die Zeilen iteriert ist korrekt. Woran genau scheitert es denn? Denn ob du nun über die Liste iterierst, die .readlines() liefert, oder über die Zeilen ist doch vom Verständnis her gleich.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man iteriert über die Datei, das liefert einem die Zeilen.

Code: Alles auswählen

for line in text_file:
    …
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Man benutzt keine kryptischen Abkürzungen. `ap` für argument_parser? `x` für eine Zeile?
Warum gefällt Dir der Attributzugriff für die Argumente nicht? Traditionell haben lange Argumente zwei Minus, aber da es sich hier eh um zwingende Argumente und keine Optionen handelt, sollten die auch nicht als Optionen angegeben werden. Der Hilfe-Text ist wenig hilfreich.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 4 und mal 8.
Man stückelt keine Strings per + zusammen, sondern nutzt Format-Strings.

Code: Alles auswählen

import argparse

def parse_args():
    argument_parser = argparse.ArgumentParser()
    argument_parser.add_argument("outfile", help="The filename for the output")
    argument_parser.add_argument("infile", help="The input filename")
    argument_parser.add_argument("insearch", help="The search string")
    return argument_parser.parse_args()

def main():
    args = parse_args()
    output_filename = args.outfile
    input_filename = args.infile
    search_string = args.insearch

    with open(output_filename, 'w', errors='ignore', encoding='utf-8') as output:
        with open(input_filename, errors='ignore', encoding='utf-8') as lines:
            for num, line in enumerate(lines,1):
                if search_string in line:
                    output.write(f"Line: {num} found: {line}")

if __name__ == "__main__":
    main()
Jetzt mußt Du natürlich noch Variablen previous_line, current_line und next_line passend führen, weil beim zeilenweisen Lesen Du ja nur auf die aktuelle Zeile Zugriff hast.
Was soll passieren, wenn der Suchtext in der ersten oder letzten Zeile gefunden wird?
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und natürlich noch die Frage was passieren soll wenn der Suchtext in mehr als einer aufeinanderfolgenden Zeile gefunden wird, oder in Zeilen bei denen eine Zeile ohne Suchtext dazwischen ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Danke Sirius! Ich habe sehr viel gelernt. Wenn ich es richtig verstehe, habe ich bei "meinem" Code alle Zeilen vollständig
eingelesen und konnte dann bei einem Treffer die Zeile davor und danach relativ einfach ausgeben. Das Problem war hier
natürlich, dass diese Methode bei großen Dateien nicht funktioniert.

Mit Deinem Code (der hervorragend funktioniert) lese ich jetzt alle Zeilen einzeln aus. Wenn der Treffer in der ersten oder
letzten Zeile ist, würde ich die Ausgabe einfach "leer" lassen. Das Auswerfen der Zeile davor und danach ist
jetzt nicht so einfach mehr möglich, da sie nicht im "Speicher" sind. Also muss ich bei einem Treffer die Zeile davor und
danach zusätzlich irgendwie auslesen, richtig?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein. Du musst die nicht auslesen, du musst sie aufheben. Zb indem du immer die drei letzten Zeilen aufhebst & die mittlere durchsuchst. Dazu kann man die dequeue-Datenstruktur benutzen.
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Nebenbemerkung: Im Grunde programmierst du dir ein vereinfachtes grep nach. Das kann alles, wonach du gefragt hattest (Kontext davor/danach, Zeilennummern) und mehr. Als Übung kann es nett sein, sich so etwas selbst zu programmieren (es gibt auch diverse Python-Implementationen davon, von denen man sich inspirieren lassen kann.) Nötig ist das aber eigentlich nicht.
Antworten