2017-04-27 3 views
0

Ich habe nur in Python für die letzten 8 Monate programmiert, also bitte entschuldigen Sie meine wahrscheinlich noob Ansatz zu Python.Python, Entfernen bestimmter langer Textzeilen in Datei

Mein Problem ist das Folgende, was ich hoffe, jemand könnte mir helfen, zu lösen.

Ich habe viele Daten in einer Datei, zum Beispiel so etwas wie dieses (nur ein Schnipsel):

SWITCH MGMT IP;SWITCH HOSTNAME;SWITCH MODEL;SWITCH SERIAL;SWITCH UPTIME;PORTS NOT IN USE 
10.255.240.1;641_HX_3560X;WS-C3560X-24P-S;FDO1601V031;12 weeks, 3 days, 23 hours, 33 minutes;1 
10.255.240.7;641_HX_LEFT_2960x;WS-C2960X-24PS-L;FOC1750S2E5;12 weeks, 4 days, 7 minutes;21 
10.255.240.8;641_UX_BASEMENT_2960x;WS-C2960X-24PS-L;FOC1750S2AG;12 weeks, 4 days, 7 minutes;12 
10.255.240.9;641_UX_SPECIAL_2960x;WS-C2960X-24PS-L;FOC1750S27M;12 weeks, 4 days, 8 minutes;25 
10.255.240.2;641_UX_OFFICE_3560;WS-C3560-8PC-S;FOC1202U24E;2 years, 30 weeks, 3 days, 16 hours, 43 minutes;2 
10.255.240.3;641_UX_SFO_2960x;WS-C2960X-24PS-L;FOC1750S2BR;12 weeks, 4 days, 7 minutes;14 
10.255.240.65;641_HX_3560X;WS-C3560X-24P-S;FDO1601V031;12 weeks, 3 days, 23 hours, 34 minutes;1 
10.255.240.5;641_HX_RIGHT_2960s;WS-C2960S-24PS-L;FOC1627X1BF;12 weeks, 4 days, 12 minutes;16 
10.255.240.6;641_HX_LEFT_2960x-02;WS-C2960X-24PS-L;FOC1750S2C4;12 weeks, 4 days, 7 minutes;15 
10.255.240.4;641_UX_BASEMENT_2960s;WS-C2960S-24PS-L;FOC1607Z27T;12 weeks, 4 days, 8 minutes;3 
10.255.240.62;641_UX_OFFICE_3560CG;WS-C3560CG-8PC-S;FOC1646Y0U2;15 weeks, 5 days, 12 hours, 15 minutes;6 

Ich möchte durch alle Daten in der Datei laufen und überprüfen, ob eine Seriennummer mehr auftritt als einmal. Wenn es das möchte, möchte ich das gefundene Duplikat entfernen. Der Grund, warum das Ergebnis den gleichen Switch oder Router mehrfach enthält, ist, dass es möglicherweise mehrere Layer 3-Schnittstellen hat, auf denen es verwaltet werden kann.

Also im obigen Beispiel. Nachdem ich durch die Daten ausgeführt haben sollte es die Zeile entfernen:

10.255.240.65;641_HX_3560X;WS-C3560X-24P-S;FDO1601V031;12 weeks, 3 days, 23 hours, 34 minutes;1 

Da die zweite Zeile bereits in der Datei die gleichen Schalter und die Seriennummer enthält.

Ich habe mehrere Tage damit verbracht, herauszufinden, wie man das erreicht und es beginnt, mir Kopfschmerzen zu bereiten.

Meine Basis-Code sieht wie folgt aus:

if os.stat("output.txt").st_size != 0: 
    with open('output.txt','r') as file: 
     header_line = next(file) # Start from line 2 in the file. 

    data = [] # Contains the data from the file. 
    sn = [] # Contains the serial numbers to check up against. 
    ok = [] # Will contain the clean data with no duplicates. 

    data.append(header_line.split(";")) # Write the head to data. 

    for line in file: # Run through the file data line for line. 
     serialchk = line.split(";") # Split the data into a list 
     data.append(serialchk) # Write the data to data list. 
     sn.append(serialchk[3]) # Write the serial number to sn list. 

end = len(data) # Save the length of the data list, so i can run through the data 
i = 0 # For my while loop, so i know when to stop.' 

while i != end: # from here on out i am pretty lost on how to achieve my goal. 
     found = 0 
     for x in range(len(data)): 
      if sn[i] == data[x][3]: 
       found += 1 
       print data[x] 
       ok.append(data[x]) 
      elif found > 1: 
       print "Removing:\r\n" 
       print data[x-1] 
       del ok[-1] 
       found = 0 
     i += 1 

Gibt es eine pythonic Weg, dies zu tun? Ich bin mir ziemlich sicher mit all den talentierten Leuten hier, dass mir jemand Hinweise geben kann, wie man das schafft.

Vielen Dank im Voraus.

+0

Zunächst einmal würde ich das ['csv'-Modul] (https://docs.python.org/3/library/csv.html) überprüfen – Kendas

Antwort

0

Mein Vorschlag:

if os.stat("output.txt").st_size != 0: 
    with open('output.txt','r') as file: 
     header_line = next(file) # Start from line 2 in the file. 

    srn = set() # create a set where the seen srn will be stored 
    ok = [] # Will contain the clean data with no duplicates. 

    ok.append(header_line.split(";")) # Write the head to ok. 

    for line in file: # Run through the file data line for line. 
     serialchk = line.split(";") # Split the data into a list 
     if serialchk[3] not in srn: # if the srn hasn't be seen 
      ok.append(serialchk) # add the row to ok 
      srn.add(serialchk[3]) # add the srn to seen set 
     else: # if the srn has already be seen 
      print "Removing: "+";".join(serialchk) # notify the user it has been skipped 

Sie werden mit ok, die nur Zeilen mit uniq srn am Ende, und drucken Sie die entfernten Zeilen Hoffentlich kann es helfen,

+0

Warum deduplizierten Zeilen im Speicher speichern, wenn Sie nur in sie schreiben können Datei direkt? –

+1

Weil es nirgends angegeben wurde, wollte @Cown es am Ende in eine Datei schreiben. – Trolldejo

+1

Duh! Ja in der Tat - sollte zweimal gelesen haben, bevor Sie kommentieren (und ich sollte mir vielleicht noch einen Kaffee xD). –

1

Sie machen es viel komplizierter als es sein muss, und nicht speicherfreundlich (Sie müssen nicht die gesamte Datei in den Speicher laden, um Duplikate zu filtern).

Der einfache Weg ist, Ihre Datei Zeile für Zeile zu lesen und für jede Zeile zu überprüfen, ob die Seriennummer bereits gesehen wurde. Wenn ja, die Zeile überspringen, speichern sonst die Seriennummer und die Zeile in die Ausgabedatei schreiben:

seen = set() 
with open('output.txt','r') as source, open("cleaned.txt", "w") as dest: 
    dest.write(next(source)) # Start from line 2 in the file. 
    for line in src: 
     sn = line.split(";")[3] 
     if sn not in seen: 
      seen.add(sn) 
      dest.write(line) 
     # else, well we just ignore the line ;) 

NB: Ich nehme an, Sie die deduplizierten Zeilen in eine Datei schreiben zurück wollen. Wenn Sie sie im Speicher behalten möchten, ist der Algorithmus meistens derselbe, fügen Sie stattdessen Ihre deduplizierten Zeilen an eine list an - aber hüten Sie sich vor der Speichernutzung, wenn Sie riesige Dateien haben.

+0

Vielen Dank dafür. Wenn es in Python ein Wort für einen Jedimaster gibt, bin ich mir ziemlich sicher, dass du einer bist. Ihr Beispiel verwendet fast keinen Speicher wie Sie angegeben haben und das Skript läuft noch schneller. Vielleicht bist du ein Python-Gott? Hmm. – Cown

+0

@Cown Das hat eigentlich nur wenig mit Python-Skills zu tun, es sind nur einfache grundlegende Algorithmen. –

+0

Ich denke, ich bin dann nicht so gut in Algorithmen, aber hey, wir müssen alle irgendwie lernen. Wäre aber nett, Python so zu sehen, wie du es tust. :-) – Cown

-1

Ich werde Sie durch die Änderungen führen, die ich machen würde.

Das erste, was ich tun würde wäre, das csv-Modul zu verwenden, um die Eingabe zu analysieren. Da Sie über die DictReader iterieren können, entscheide ich mich auch für die Kürze. Die listdata enthält die endgültigen (bereinigten) Ergebnisse.

from csv import DictReader 
import os 

if os.stat("output.txt").st_size != 0: 
    with open('output.txt', 'r') as f: 
     reader = DictReader(f, delimiter=';') # create the reader instance 

     serial_numbers = set() 
     data = [] 
     for row in reader: 
      if row["SWITCH HOSTNAME"] in serial_numbers: 
       pass 
      else: 
       data.append(row) 
       serial_numbers.add(row["SWITCH HOSTNAME"]) 

Das Format der Daten wird von meinem Ansatz, von einem list s list von zu einem list von dict s geändert haben, aber wenn Sie möchten die gereinigten Daten in eine neue CSV-Datei, die DictWriter Klasse speichern sollte eine einfache Möglichkeit sein, das zu tun.

+0

Hallo Herr, ich bin nicht sicher, warum Sie davon ausgehen, dass meine Daten eine CSV-Datei ist, ist es nicht. Es sind einfach nur Textdaten, die ich aus dem Ausführen und Einloggen in Switches usw. extrahiert habe. Es ist durch Semikolon getrennt, damit es zum Beispiel leichter in Excel importiert werden kann. Danke für das obige Beispiel, aber es ist nicht das, wonach ich suche. :-) – Cown

+0

csv bedeutet 'Komma getrennte Werte'. Während technisch Ihre Werte durch Semikola getrennt sind, ist das Format das gleiche. Die erste Zeile enthält einen Header mit Werten, die durch das Trennzeichen (';') getrennt sind. Nachfolgende Zeilen enthalten Datenwerte, die wiederum durch das Trennzeichen getrennt sind. Sehen Sie sich das letzte [Beispiel] (https://en.wikipedia.org/wiki/Comma-separated_values#Example) in Wikipedia an. – Kendas

Verwandte Themen