Python Liste Textdatei zwei Zeilen hintereinander löschen

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
Kato1998
User
Beiträge: 3
Registriert: Donnerstag 2. März 2023, 21:23

Hallo :D

Ich möchte ein Python Scrip schreiben in dem eine Textdatei eingelesen wird und dann, wenn in einer Zeile ein "up" vorkommt, wird die Zeile gelöscht wird und auch die nächste Zeile in der Liste

Hier ein Beispiel von meiner Text Datei
Name/0/2 is up, line protocol is up (verbunden)
Letzter input 00:01:33, output 00:00:06, abc abc abc
Name/0/2 is down, line protocol is down (getrennt)
Letzter input 20w0d, output 20w0d, abc abc abc
Name/0/3 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/4 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/5 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/6 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/7 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/8 is down, line protocol is down (getrennt)
Letzter input 18:30:15, output 18:29:38, abc abc abc
Name/0/9 is up, line protocol is up (verbunden)
Letzter input 1w2d, output 00:00:06, abc abc abc
Name/0/10 is up, line protocol is up (connected)
Letzter input 00:00:41, output 00:00:06, abc abc abc

Hier mein Programm:

Code: Alles auswählen

dat_auswertung = open(test.text)

for zeile in dat_auswertung:

    daten.append(zeile.split(" ")) 
    
dat_auswertung.close()


y=0
for x in daten:
    if "up" in daten[y][2]:
        print (y)
        print (daten[y][2])
        daten.pop(y)
        print (daten[y][2])
        daten.pop(y)
 y=y+1

Leider löscht es nicht alle Zeilen sondern nur manche :/
Benutzeravatar
Dennis89
User
Beiträge: 1556
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

kannst du erklären, wieso das ' y=y+1' an der Stelle steht, an der es gerade ist und welche Auswirkung das auf das Programm hat. Und wieso zwei mal 'pop(y)' ?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Code ist nicht lauffähig, weil die Einrückungen nicht stimmen. `daten` wird nirgends definiert.
Dateien öffnet man immer innerhalb eines with-Statements und gibt das passende Encoding an.
`x` ist ein sehr schlechter Variablenname für die Teile einer Zeile.
Einen Index benutzt man nicht, vor allem nicht, wenn man ihn auch noch händisch zählt. Wenn man Zeilen aus einer Liste löscht, ändern sich auch die nachfolgenden Indices, was man aber auch nicht macht, weil man einfach eine neue Liste mit dem korrekten Inhalt erzeugt.

Code: Alles auswählen

with open(test.text, encoding="utf8") as zeilen:
    daten = []
    skip_next = False
    for zeile in zeilen:
        if skip_next:
            skip_next = False
        else:
            teile = zeile.split(" ")
            if "up" in teile[2]:
                skip_next = True
            else:
                daten.append(teile)
Die Frage ist aber, ob Du wirklich in jeder Zeile nach up suchen willst, da ja offensichtlich immer zwei Zeilen zusammengehören.
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Ich wollte gerade das vorschlagen

Code: Alles auswählen

dat_auswertung = []
with open("test.txt", "r") as f:
    dat_auswertung = f.read().splitlines()
    
for i, zeile in reversed(list(enumerate(dat_auswertung))):
    if "up" in zeile:
        dat_auswertung.pop(i)
        dat_auswertung.pop(i)
        
print("\n".join(dat_auswertung))
Name/0/2 is down, line protocol is down (getrennt)
Letzter input 20w0d, output 20w0d, abc abc abc
Name/0/3 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/4 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/5 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/6 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/7 is down, line protocol is down (getrennt)
Letzter input never, output never, abc abc abc
Name/0/8 is down, line protocol is down (getrennt)
Letzter input 18:30:15, output 18:29:38, abc abc abc
OS: LMDE5 *** Homepage *** Github Seite
Benutzeravatar
snafu
User
Beiträge: 6872
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Code: Alles auswählen

with open("test.log") as stream:
    while (line := stream.readline()):
        next_line = stream.readline()
        if "up" not in line.split():
            print(line, end="")
            print(next_line, end="")
Könnte man auch ohne readline() lösen, indem man diverse Iteratoren verschachtelt, aber ich fand es so einfach direkter. Das Ergebnis ist am Ende das selbe. Das Wesentliche hier ist, dass keine Listen benutzt werden. Damit schont man den Arbeitsspeicher und kann somit mühelos riesige Logfiles verarbeiten.

Aus Spaß an der Freude hier dennoch eine Variante unter Verwendung des externen ``more_itertools``-Moduls:

Code: Alles auswählen

from more_itertools import chunked, flatten

def filter_non_ups(stream):
    return flatten(
        pair for pair in chunked(stream, 2)
        if "up" not in pair[0].split()
    )

def main():
    with open("test.log") as stream:
        for line in filter_non_ups(stream):
            print(line, end="")

if __name__ == "__main__":
    main()
Beide verwendeten Funktionen des Moduls lassen sich auch relativ leicht mit den Möglichkeiten der Standardbibliothek nachbauen:

Code: Alles auswählen

from itertools import chain

def chunked(iterable, n):
    return zip(*[iter(iterable)] * n)

def filter_non_ups(stream):
    return chain.from_iterable(
        pair for pair in chunked(stream, 2)
        if "up" not in pair[0].split()
    )

def main():
    with open("test.log") as stream:
        for line in filter_non_ups(stream):
            print(line, end="")

if __name__ == "__main__":
    main()
Also zumindest für diesen Anwendungsfall. Im Detail verhält sich das more_itertools chunked() etwas anders, da es nicht auf zip() basiert.
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wie wäre es mit einem schönen Generator::

Code: Alles auswählen

def get_lines_without_up(fname):
    with open(fname) as fobj:
        for line in fobj:
            if "up" in line.split():
                next(fobj)
            else:
                yield line
                
for line in get_lines_without_up("lines.txt"):
    print(line.strip())
Benutzeravatar
snafu
User
Beiträge: 6872
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@kbr
``for`` und ``next()`` waren auch meine ersten Ideen. Am frühen Morgen war ich aber anscheinend zu doof für die Umsetzung. Hatte immer doppelte Zeilen in der Ausgabe, keine Ahnung warum. So wie dein Aufbau ist, klappt es natürlich. Das würde ich einem readline() auch vorziehen.

EDIT: Zur Sicherheit könnte man auch next(fobj, "") oder next(fobj, None) schreiben. Dann wird kein Fehler geworfen, falls die Datei aus irgendwelchen Gründen schon vor der letzten Folgezeile endet. Stattdessen gibt er den übergebenen Default-Wert zurück, den man dann natürlich ignorieren kann.
Antworten