2 .txt-Dateien miteinander vergleichen

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
eNtrY
User
Beiträge: 5
Registriert: Mittwoch 18. Januar 2012, 11:24

Hallo zusammen,

vorab einmal als Warnung. Ich bin nicht der größte Programmierer.

Zum eigentlichen Thema:
Ich bin derzeit dabei ein Skript zu schreiben, welches zwei .txt-Dateien miteinander vergleicht und ggf. in die Gesamt-Tabelle was einträgt.

Und zwar gibt es einmal die "Neuen"-Dateien (Testweise 2 Stück, später bis zu 10 - 15) und einmal die "Gesamt"-Datei.
In der Gesamtdatei sollen alle Einträge gesammelt werden, aber keine doppelten... Des Weiteren soll immer die Gesamttabelle mit der "Neuen" verglichen werden und neue Einträge in die gesamttabelle eingetragen werden.

Mein momentaner Stand:

Code: Alles auswählen

import os

# Anzahl der Switch-Dateien
count_dat = 1

while count_dat < 3: # Anzahl der Dateien+ 1
    # Dateien
    gesamt = "C:\\Users\\xxx\\Desktop\\vorhanden.txt"
    vergleich = "C:\\Users\\xxx\\Desktop\\neu"+str(count_dat)+".txt"

    # einlesen
    gd = open(gesamt, "r")
    gesamt_data = gd.readlines()
    gd.close()

    vd = open(vergleich, "r")
    vergleich_data = vd.readlines()
    vd.close()

    count_ver = 0

    for line in vergleich_data:
        for line in gesamt_data:
            if gesamt_data.line == vergleich_data.line:
                count_ver = 1
            else:
                continue
        
            if count_ver == 1:
                continue
            else:
                gd2 = open(gesamt, "a")
                gd2.write(gesamt_data.line)
                gd2.close()
                count_ver = 0

    count_dat += 1
    print "Counter +1"

print "Finished"
Momentan bin ich so weit, allerdings schaffe ich es nicht Zeile für Zeile der beiden Dateien miteinander zu vergleichen.

Vergleich Zeile 1 <-> Gesamt Zeile 1
Vergleich Zeile 1 <-> Gesamt Zeile 2
... und so weiter ... und wieder von vorne...
Vergleich Zeile 2 <-> Gesamt Zeile 1
Vergleich Zeile 2 <-> Gesamt Zeile 2

Des Weiten schaffe ich es iwie nicht ein <= einzubauen (siehe oben count_dat) - daher auch die Anmerkung: Switche + 1

Hat wer 'nen Tipp für mich wie ich das machen kann?

Vielen Dank im Voraus.

Gruß,

Steven

Edit: Text abgeändert.
Zuletzt geändert von eNtrY am Mittwoch 18. Januar 2012, 12:18, insgesamt 2-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo und Willkommen im Forum!
eNtrY hat geschrieben: vorab einmal als Warnung. Ich bin der größte Programmier- bzw. Skriptschreiber!
Ein heftiger Satz zu Beginn einer Foren-"Karriere" - fehlt da nicht ein Smiley? ;-)
eNtrY hat geschrieben: Zum eigentlichen Thema:
Ich bin derzeit dabei ein Skript zu schreiben, welches zwei .txt-Dateien miteinander vergleich und ggf. in die Gesamt-Tabelle was einträgt.
Anstatt über die Mechanismen zu philosophieren, welche Dateien wieso verglichen werden, hättest Du mal etwas über die *Art* des Vergleiches schreiben sollen! Was sind das für Daten? Wie kann man die denn vergleichen?

Generell sieht der Code ziemlich unpythonisch und wirr aus.

- Als erstes könntest Du die speziellen Python-Code-Tags benutzen, um Python-Code hier im Forum zu posten.

- die `while`-Schleife ist hier ungünstig - wenn man die Anzahl an Durchläufen kennt, sollte man eine `for`-Schleife nutzen:

Code: Alles auswählen

for _ in xrange(LIMIT):
- Was sind `switche`?

- Dateien sollte man so öffnen:

Code: Alles auswählen

with open(...) as handler:
    # handler ist in diesem Block das File-Objekt
- Generell solltest Du immer Funktionalität aus der Modulebene in Funktionen packen. Wenn ich zweimal eine Textdatei komplett zeilenweise einlese, dann kann ich das doch in eine Funktion auslagern

Ohne genauere Angaben (s.o.) kann ich Dir erst einmal nicht weiterhelfen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
eNtrY
User
Beiträge: 5
Registriert: Mittwoch 18. Januar 2012, 11:24

Hallo und Danke.

Zu deinem ersten Punkt, gibt es zu meiner Verteidigung nur eines zu sagen. Ich hab mich verschrieben bzw. ein Wort vergessen :D

Code: Alles auswählen

1    xx:xx:xx:xx:xx:xx        learned         ---     bridging       1/1  
1    xx:xx:xx:xx:xx:xx        learned         ---     bridging       1/18 
1    xx:xx:xx:xx:xx:xx        learned         ---     bridging       1/33


Das steht in den jeweiligen Dateien drin. Wenn es die gleiche Zeile bereits in der Gesamt.txt gibt soll nichts getan werden, ansonsten soll die Zeile unten angehängt werden.
Daher auch das:

Code: Alles auswählen

gd2 = open(gesamt, "a")
Die while-Schleife hatte ich nur benutzt, da ich dachte das danach das <=-Zeichen funktioniert - vorgesehen war for.

Zum meinem Code:
Ich bin wie gesagt, ich programmiere eher selten und kenn mich daher nicht so gutaus.
Ich hab das Tag oben im ersten Post angepasst und nun das pyhton-Tag verwendet.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Falls du die Vereinigung von zwei Dateien in eine neue packen willst, reicht folgender Code-Schnipsel aus:

Code: Alles auswählen

input1 = input2 = output = []

with open("input1.txt", "r") as inputfile1:
	input1 = inputfile1.read().split("\n")
with open("input2.txt", "r") as inputfile2:
	input2 = inputfile2.read().split("\n")
with open("output.txt", "w") as outputfile:
	outputfile.write("\n".join(sorted(set(input1) | set(input2))))
Bzw. das ganze verallgemeinert angewandt wenn du anhängen willst, weniger Vergleiche anstellen, mehr schreiben oder was auch immer.
eNtrY
User
Beiträge: 5
Registriert: Mittwoch 18. Januar 2012, 11:24

Wichtig ist einfach nur, dass in der Gesamt.txt keine doppelten Einträge reinkommen.
Wenn das deine Verzweigung macht ist das top.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Probier es doch einfach aus. Zumindest mit Python 2 scheint es für mich wunderbar zu laufen.

Achja, Sets (zumindest die eingebauten, die ich hier verwende) arbeiten nicht sortiert. Weswegen ich hinterher die Vereinigung sortiere. Ich hoffe du verstehst die wenigen Zeilen, wenn nicht, dann frag nach, denn sie sind nämlich nicht dazu gedacht ins Skript kopiert zu werden, sondern einen möglichen Lösungsansatz zu erläutern.
BlackJack

@eNtrY: Weitere Anmerkungen:

Statt ``+`` und `str()` kann man Zeichenkettenformatierung mit dem ``%``-Operator oder der `format()`-Methode auf Zeichenketten verwenden. Das ist übersichtlicher und flexibler.

Der Algorithmus den Du in Worten beschreibst, ist ineffzient. Jede Zeile einer Datei mit jeder anderen Zeile einer anderen Datei zu vergleichen hat quadratische Laufzeit. Wenn es immer um die kompletten Zeilen geht, dann solltest Du besser die Gesamtdatei in ein `set()` einlesen und dann mit dem ``in``-Operator prüfen, ob eine Zeile der anderen Dateien dort vorhanden ist. Beziehungsweise den ``not in``-Operator, wenn Du testen möchtest, ob die Zeile nicht enthalten ist.

Dein Quelltext funktioniert *so* überhaupt nicht, denn das sollte mit einem `AttributeError` abbrechen. Wenn wir nach Quelltext fragen, dann normalerweise nach dem, den Du *tatsächlich* verwendest, und nicht welcher der so ähnlich aussieht, aber nicht funktioniert, oder zumindest sich nicht anders verhält, als Du es im Text beschreibst.

Die Logik in der innersten Schleife ist recht umständlich. Für jede neue Zeile die Gesamtdatei öffnen und schliessen, ist vielleicht auch etwas unperformant.

Namen sollte man möglichst nicht abkürzen, solange sie nicht in einem sehr eng begrenzten Bereich gültig sind, oder die Abkürzung allgemein bekannt ist. Und durchnummerieren sollte man Namen nach möglichkeit auch nicht. Dann hat man meistens zu viel in einer Funktion stehen oder man möchte eine Liste verwenden. Im vorliegenden Fall ist es aber schlicht unnötig die 2 an `gd` zu hängen, denn der Name könnte an der Stelle auch problemlos noch einmal verwendet werden.

@webspider: Die erste Zeile ist überflüssig. `input1` und `input2` werden auf jeden Fall neu gebunden und `output` wird noch nicht einmal verwendet.

Ansonsten verbrauchst Du unnötig Speicher und machst Dir zu viel Arbeit. Statt an Zeilenenden zu teilen und am Ende mit Zeilenenden wieder zusammen zu fügen, könntest Du auch einfach die Zeilen (mit Zeilenenden) einlesen. Also ``input1 = list(inputfile1)``. Und beim Schreiben dann die `writelines()`-Methode.

Statt alles komplett in Listen einzulesen, Mengen von beiden komplett eingelesenen Listen zu erzeugen, daraus dann die Vereinigungsmenge zu erzeugen, könnte man etwas mehr „lazy” arbeiten. Zum Beispiel die Zeilen der ersten Datei gleich in ein `set()` stecken und das mit den Zeilen der zweiten Datei direkt aktualisieren, ohne den Umweg über eine Liste oder eine Menge. Ungetestet:

Code: Alles auswählen

with open('input1.txt', 'r') as lines:
    unique_lines = set(lines)
with open('input2.txt', 'r') as lines:
    unique_lines.update(lines)
with open('output.txt', 'w') as output_file:
    outputfile.writelines(sorted(unique_lines))
eNtrY
User
Beiträge: 5
Registriert: Mittwoch 18. Januar 2012, 11:24

Bei deinem Code steig ich nicht richtig durch, aber nunja. Ich bekomme folgende Fehlermeldung:
Warning: 'with' will become a reserved keyword in Python 2.6

Auf dem jeweiligen Client, wo das Programm laufen soll ist derzeit 2.5 installiert.

Gibt es keinen anderen Weg (Am besten wäre halt für mich "einfacher" Code ^,^)

Gruß



Edit:
Das ist der Code den ich verwende, wie du schon meintest ist er nicht lauffähig. Ich werde mir mal die set()-Geschichte anschauen und hoffen das ich damit meine .txt richtig updaten kann.
Zuletzt geändert von eNtrY am Mittwoch 18. Januar 2012, 12:59, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

eNtrY hat geschrieben:Bei deinem Code steig ich nicht richtig durch, aber nunja.
Wieso nicht? Welche Stelle kapierst Du denn nicht?
eNtrY hat geschrieben: Ich bekomme folgende Fehlermeldung:
Warning: 'with' will become a reserved keyword in Python 2.6
Das kannst Du mittels

Code: Alles auswählen

from __future__ import with_statement
auch schon in 2.5 bekommen.

Wenn Du so eine alte Version benutzt, solltest Du das auch angeben!

Gibt es dafür denn einen trifftigen Grund? Wenn nein, solltest Du schon auf 2.7 updaten.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
eNtrY
User
Beiträge: 5
Registriert: Mittwoch 18. Januar 2012, 11:24

Das mit dem

Code: Alles auswählen

from __future__ import with_statement
Wusste ich nicht, danke schon einmal dafür.
Zu der Problematik mit der alten Version, das Script läuft derzeit auf einem Server wo schon einige Python-Scripte laufen, welche von jemand anders geschrieben wurden.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

@BlackJack: Vielen Dank für die Verbesserung (optimierte und versäumte anscheinend die ungenutzte Variable rauszunehmen), ich hab grad deinen Code getestet. Wenn man den einen Syntax-Fehler entfernt, funktionierts aber nur fast richtig. Ist input1 [a, b, c, d, e] und input2 [b, c, d, e, f], erhalte ich als Ausgabe [a, b, c, d, ee, f]. Dass beim Öffnen von Dateien mit dem with-Statement diese als Zeilen interpretiert werden können ohne extra Trennen zu müssen, wusste ich bisher nicht.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

eNtrY hat geschrieben: Zu der Problematik mit der alten Version, das Script läuft derzeit auf einem Server wo schon einige Python-Scripte laufen, welche von jemand anders geschrieben wurden.
Naja, innerhalb der 2er Linie ist Python ja abwärts kompatibel - Du kannst also ohne Gefahr die Version updaten! Und wenn das nicht geht, dann musst Du eben mit 2.5 klar kommen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@webspider: Dann sind nicht alle Zeilen mit einem '\n' abgeschlossen.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

@BlackJack: Korrekt, war die letzte Zeile in der ersten Datei, da ich sie mit str.join(list) erstellt hab und dieses den Trenner nicht ans Ende der Liste packt. Da es nicht ungewöhnlich wäre dass sowas in der Praxis vorkommt, würde ich evtl. noch eine kleine Überprüfung mit reinwerfen. Ansonsten ist dein Code-Schnipsel sehr elegant arbeitend.
Antworten