Zwei 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
meex87
User
Beiträge: 4
Registriert: Dienstag 10. Juli 2018, 18:43

Hallo,

eines vorab:
Ich bin neu in Python bzw. allgemein in der Programmierung.
Das einzige was ich bisher damit zu tun hatte ist einfachen programmieren an Siemens Sinumerik Steuerungen.
Dies funktioniert mit ähnlichen Operatoren als Python bzw. wie fast jede Programmiersprache ( IF ELSE WHILE usw.)
Mein bisheriger Lösungsansatz wird deshalb auch nicht der schnellste Weg sein :) . Sondern eher so wie ich es mit meinem bisherigen Kentnissen programmiert hätte :)

Ich will ein Script erstellen indem zwei TXT Dateien miteinander verglichen werden.
Sagen wir mal NamenIst.TXT und NamenSoll.TXT.
In diesen beiden Dateien steht in jeder Zeile ein Name:
z.B. NamenIst.TXT:
Hans
Peter
Lars
Niclas
Max
usw....

z.B. NamenSoll.TXT:
Juergen
Henrik
Erik
Max
Peter

Ich möchte die beiden Listen miteinander vergleichen und ausgeben (in eine neue TXT) welche Namen in der IST-Liste nicht vorhanden sind aber in der SOLL.

Also erst mal Namen auslesen:

Code: Alles auswählen

f = open('NamenIst.txt','r')
istname1 = f.readline()
istname2 = f.readline()
istname3 = f.readline()
istname4 = f.readline()
istname5 = f.readline()
istname6 = f.readline()
istname7 = f.readline()
istname8 = f.readline()
istname9 = f.readline()
istname10 = f.readline()
f.close()

f = open('NamenSoll.txt','r')
sollname1 = f.readline()
sollname2 = f.readline()
sollname3 = f.readline()
sollname4 = f.readline()
sollname5 = f.readline()
sollname6 = f.readline()
sollname7 = f.readline()
sollname8 = f.readline()
sollname9 = f.readline()
sollname10 = f.readline()
f.close()
Hier gibt es bestimmt schnellere Methoden. :)

Als nächstes sollte dann Jeder istname mit jedem sollnamen vergleichen werden.
Das hatte ich bisher in meiner Siemens Steuerunge so gelöst:

Code: Alles auswählen

NEXTNAME:
IF ISTNAME[ZAEHLERN] == SOLLNAME[ZAEHLERO]
GOTOB NEXTNAME
Wobei hier der Zähler dann immer jeweils um 1 erhöht wurde.
Frage 1:
Soweit ich gelesen habe gibt es in Python keine Sprungbefehle.. Also kein GOTO usw ? Richtig ?

Frage 2:
Ich möchte eine StringVariable (z.B. TEST) mit einem Integer(z.B. ZAEHLER) kombienieren. Das ganze dann im einer IF Abfrage "zusammenbauen)
Beispiel:
TEST = Hallo
ZAEHLER = 5
IF TEST[ZAEHLER] == 5
print("Zaehler ist 5)

irgendwie funktioniert das leider nicht so wie bei meiner Siemens Steuerung :)

Danke im Vorraus für eure Hilfe.

Grüße
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Ich kenne die Programmiersprache der Steuerung, die du nennst nicht. Die Beispiele sehen aber nach einer relativ rudimentären imperativen Sprache aus, die mich ein bisschen an Basic erinnert. Python funktioniert da deutlich anders und ich fürchte, da wirst du dich umgewöhnen müssen :). Ein guter Einstieg ist das in der Doku enthaltene, offizielle Tutorial.

Ja, in Python gibt es kein Goto. Der Konsens ist im Allgemeinen, dass Goto eine ganze schlechte Idee ist und auch in Sprachen, die das haben, möglichst vermieden werden sollte.
Alle Verwendungen von Goto lassen sich durch Kontrollstrukturen (Schleifen, Verzweigungen) abbilden.

Deine zweite Frage haben ich wegen des Beispiels nicht ganz verstanden. Strings fügt in Python bevorzugt mit der String-Methode 'format' zusammen. '"hallo {}".format(5)' ergibt "hallo 5".

Ansonsten noch zu deinem Vorhaben: Man kann mit einer Schleife direkt über eine Datei iterieren:

Code: Alles auswählen

with open('test.txt') as f:
    for line in f:
        print(line.strip())
Für Vergleiche, wie den, den du beschrieben hast, bietet sich der 'set' Datentyp an.
Zuletzt geändert von nezzcarth am Dienstag 10. Juli 2018, 19:52, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@meex87: Wenn Du anfängst Namen durchzunummerieren dann willst Du in aller Regel eine Datenstruktur verwenden. Meistens eine Liste (`list`), in diesem Fall eher eine Menge (`set`), weil Du das einfach mit Mengenoperationen lösen kannst.

Da das Einlesen in beiden Fällen bis auf den Namen der Variable identisch ist, an die das am Ende gebunden wird, solle man das in eine Funktion auslagern um es nicht zweimal hinschreiben zu müssen.

Zähler als Index sind in Python sehr selten. Immer wenn Du das machen willst, solltest Du innehalten und überlegen ob es nicht einen ”pythonischeren” Weg ohne Laufindex gibt, denn den gibt es fast immer.

Ad Frage 1: Es gibt in der Sprache keine ``goto``-Anweisung, aber eine funktionierende Implementierung vom 1. April 2004 (http://entrian.com/goto/) und ein alternativer Ansatz als Dekorator der den Bytecode umschreibt im Package Index (https://pypi.org/project/goto-statement/). Beides eher kurios und eher nicht für den realen Einsatz.

Ausnahmen und Ausnahmebehandlung kann man zumindest in eine Richtung als ``goto``-Ersatz missbraucht, was man aber auch nicht zu exzessiv machen sollte. Es ist ja auch nicht wirklich nötig, weil Code selten besser aber oft schlechter verständlich macht.

Python ist keine Siemens-Steuerung und funktioniert dementsprechend auch nicht so wie die Programmiersprache dort. Du musst also schon Python lernen. In der Python-Dokumentation gibt es ein Tutorial das man mal durchgearbeitet haben sollte.

@nezzcarth: Ich denke der Konsens gegen GOTO ist nicht sooo stark, denn es lassen sich in Sprachen die GOTO haben oft *nicht* alle Verwendungen durch Kontrollstrukturen abbilden. In C fehlen mir beispielsweise Ausnahmen, die ich ganz gerne durch ein ``goto`` zur Fehlerbehandlung ersetze. Eine Technik die auch im Quelltext von CPython verwendet wird.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ohne das man irgendwelche Schleifen oder gar unbedingte Sprünge braucht:

Code: Alles auswählen

#!/usr/bin/env python


def main():
    with open('test.txt', 'r') as actual_names_file:
        actual_names = set(actual_names_file)
    with open('test2.txt', 'r') as target_names_file:
        target_names = set(target_names_file)
    with open('test3.txt', 'w') as diff_file:
        diff_file.writelines(target_names - actual_names)


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
meex87
User
Beiträge: 4
Registriert: Dienstag 10. Juli 2018, 18:43

__blackjack__ hat geschrieben: Dienstag 10. Juli 2018, 20:01 Ohne das man irgendwelche Schleifen oder gar unbedingte Sprünge braucht:

Code: Alles auswählen

#!/usr/bin/env python


def main():
    with open('test.txt', 'r') as actual_names_file:
        actual_names = set(actual_names_file)
    with open('test2.txt', 'r') as target_names_file:
        target_names = set(target_names_file)
    with open('test3.txt', 'w') as diff_file:
        diff_file.writelines(target_names - actual_names)


if __name__ == '__main__':
    main()
Wow.. da ist man paar Minuten nicht am PC und hat gleich soviele Antworten.
Danke!

Das man das mit ein paar Zeilen Code schafft hätte ich nicht gedacht.. was das für ein rießen Aufwand bei meiner Siemens Steuerung war..
Ich denke ich muss mich da mal ein paar Stunden damit beschäftigen :)
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

actual_names und target_names sind in obigem Beispiel sets, damit kannst du jede Menge nette Sachen machen, außer - (difference):

Code: Alles auswählen

class set([iterable])

Instances of set and frozenset provide the following operations:

len(s)
Return the number of elements in set s (cardinality of s).

x in s
Test x for membership in s.

x not in s
Test x for non-membership in s.

isdisjoint(other)
Return True if the set has no elements in common with other. Sets are disjoint if and only if their intersection is the empty set.

issubset(other)
set <= other
Test whether every element in the set is in other.

set < other
Test whether the set is a proper subset of other, that is, set <= other and set != other.

issuperset(other)
set >= other
Test whether every element in other is in the set.

set > other
Test whether the set is a proper superset of other, that is, set >= other and set != other.

union(*others)
set | other | ...
Return a new set with elements from the set and all others.

intersection(*others)
set & other & ...
Return a new set with elements common to the set and all others.

difference(*others)
set - other - ...
Return a new set with elements in the set that are not in the others.

symmetric_difference(other)
set ^ other
Return a new set with elements in either the set or other but not both.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das GOTO hat mich inspiriert dieses Problem mal auf meinem ersten eigenen Rechner in BASIC zu lösen:

Code: Alles auswählen

  100 PRINT"EINLESEN DER 'IST'-DATEN...":DIM A$(100):I=0:OPEN 2,8,2,"IST,S,R"
  110 I=I+1:INPUT#2,A$(I):IF ST=0 THEN 110
  120 CLOSE 2:PRINT I;"NAMEN EINGELESEN."
  130 IF ST<>64 THEN PRINT"FEHLER BEIM LESEN VON 'IST'.":GOTO 900
  200 PRINT:PRINT"ABGLEICH MIT 'SOLL' UND SCHREIBEN VON"
  210 PRINT"'DIFF'.":J=0:OPEN 2,8,2,"SOLL,S,R":OPEN 3,8,3,"DIFF,S,W":
  220 INPUT#2,L$:IF ST THEN 500
  230 IF I=0 THEN 400
  240 F=0:FOR J=0 TO I:IF L$=A$(J) THEN F=-1:J=I
  250 NEXT:IF F THEN 220
  400 PRINT#3,L$:GOTO 220
  500 CLOSE 2:CLOSE 3:IF ST<>64 THEN PRINT"FEHLER BEIM LESEN DER 'SOLL'-DATEN."
  900 OPEN 15,8,15:INPUT#15,E,E$,T,S:CLOSE 15:PRINT E;E$;T;S
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
meex87
User
Beiträge: 4
Registriert: Dienstag 10. Juli 2018, 18:43

Hallo,

klasse :)
Ja, für jemanden der mit GOTO usw. bisher programmiert hat ist es echt schwer darauf zu verzichten.
Bin gerade dabei mein Script etwas auszubauen.. Ich prüfe nun vorher ob die Dateien überhaupt vorhanden sind.
Klappt auch soweit.. Allerdings möchte ich, falls eine der Dateien nicht da ist die Meldung ausgeben "Datei fehlt usw...) und dann das script neustarten.
Mit GOTO wäre ich einfach wieder nach oben gesprungen, welche Lösung könnt ihr euch da mit Python vorstellen ?

Danke
Grüße
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Nun, wenn eine der Dateien nicht vorhanden ist, bringt es ja eigentlich nichts, einfach neu zu starten, oder?
Ansonsten schau mal hier rein:
https://www.python-kurs.eu/ausnahmebehandlung.php
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@meex87: in Python ist das einfach ein `if` innerhalb einer Schleife. Bei komplexeren Dingen besteht die Schleife dann nur aus einem if und einem Funktionsaufruf, so dass der Sprung auch nicht so weit ist.
meex87
User
Beiträge: 4
Registriert: Dienstag 10. Juli 2018, 18:43

ThomasL hat geschrieben: Samstag 14. Juli 2018, 09:56 Nun, wenn eine der Dateien nicht vorhanden ist, bringt es ja eigentlich nichts, einfach neu zu starten, oder?
Ansonsten schau mal hier rein:
https://www.python-kurs.eu/ausnahmebehandlung.php
Hallo,

vielen Dank.
Werde ich mir mal ankucken..
Macht in meinem Fall schon Sinn weil eine Datei von den beiden extern per Lan reinkopiert wird :)

Grüße.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@meex87: Explizit auf die Existenz von Dateien zu prüfen macht man in Python eher selten, weil zwischen dem prüfen und dem verwenden durchaus noch etwas passieren kann, die Datei beispielsweise gelöscht oder verschoben werden kann. Andererseits ist im öffnen einer Datei zum lesen der Test ob sie existiert ja bereits enthalten, denn wenn sie nicht existiert, wird eine Ausnahme ausgelöst.

Ansonsten wurde ja schon gesagt, dass man eine Schleife nimmt für Sachen die wiederholt werden sollen. Wenn man nicht genau weiss wie oft, dann eine ``while``-Schleife. Und wenn sich die Entscheidung ob der Schleifenkörper ausgeführt werden soll oder nicht, am Anfang der Schleife noch nicht teffen lässt, schreibt man mit ``while True:`` eine ”Endlosschleife” die in der Schleife dann an der entsprechenden Stelle mit einem ``break`` verlassen wird:

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    while True:
        try:
            with open('test.txt', 'r') as actual_names_file:
                actual_names = set(actual_names_file)
            with open('test2.txt', 'r') as target_names_file:
                target_names = set(target_names_file)
            with open('test3.txt', 'w') as diff_file:
                diff_file.writelines(target_names - actual_names)
            break
        except OSError as error:
            print('Fehler: {}'.format(error))
            answer = input('Noch einmal versuchen (j/n) ?')
            if not answer.lower().startswith('j'):
                break


if __name__ == '__main__':
    main()
Und hier die BASIC-Variante vom C64 an mein erstes BASIC auf dem PC angepasst (GW-BASIC) und auch mit der Wiederholung versehen wenn eine Datei nicht gefunden werden konnte:

Code: Alles auswählen

 10 ON ERROR GOTO 240
 20 '--------------------------
 30 'Einlesen der ersten Datei.
 40 '--------------------------
 50 PRINT"Einlesen der IST-Daten...":DIM A$(100)
 60 OPEN "IST.TXT" FOR INPUT AS 2
 70 I=0:WHILE NOT EOF(2):I=I+1:LINE INPUT #2,A$(I):WEND:CLOSE 2
 80 PRINT I;"Namen eingelesen."
 90 '-------------------------------------------------------------------
100 'Einlesen der zweiten Datei, dabei Abgleich mit den vorher gelesenen
110 'Daten, und ggf. Schreiben in die Ergebnisdatei.
120 '-------------------------------------------------------------------
130 PRINT:PRINT"Abgleich mit SOLL und schreiben von DIFF."
140 OPEN "SOLL.TXT" FOR INPUT AS 2:OPEN "DIFF.TXT" FOR OUTPUT AS 3
150 WHILE NOT EOF(2):LINE INPUT #2,L$:IF I=0 THEN 190
160 'Suche der gelesenen Zeile.
170 F=0:FOR J=0 TO I:IF L$=A$(J) THEN F=-1:J=I
180 NEXT:IF F THEN 200
190 PRINT#3,L$
200 WEND:CLOSE 2:CLOSE 3:END
210 '-------------------------------------------
220 'Fehlerbehandlung bei "File not found" (53).
230 '-------------------------------------------
240 IF ERR<>53 THEN PRINT ERL,:ON ERROR GOTO 0:ERROR ERR:END
250 PRINT"Datei konnte nicht gefunden werden."
260 PRINT"Drücken Sie eine Taste um es erneut zu versuchen."
270 K$=INKEY$:IF K$="" THEN 270 ELSE RESUME
Hier sind schon ein paar GOTO's verschwunden, weil es WHILE/WEND in diesem Basic-Dialekt gibt. Dazugekommen ist ON ERROR GOTO und RESUME.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten