Mehrfache Fallunterscheidung (elif) total verkompliziert

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
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

Ich habe es geschafft, eine einfache Mehrfachverzweiung so zu komplizieren, dass ich nicht mehr durchblicke (es funktioniert aber alles richtig).
Erst einmal die Beschreibung:
Folgende reguläre Ausdrücke kommen vor: (die ersten 7 sind Zahlen, die anderen 3 Strings)
squares, p1, p2, p3, p4, p5, residual, 'convergence', 'divergence', 'Matrix'

Die Textdatei, die durchsucht wird, erscheint immer wieder neu und kann wie folgt aussehen:
Entweder findet er
1. squares, p1, p2, p3, p4, p5, residual
oder
2. divergence, p1, p2, p3, p4, p5, residual
oder
3. convergence
oder
4. Matrix

Die Anweisungen danach sind bei
1. squares, p1, p2, p3, p4, p5, residual in pardatei schreiben
2. p1, p2, p3, p4, p5, residual und 'divergence' in errordatei schreiben
3. 'convergence' in errordatei schreiben
4. 'Matrix' in errordatei schreiben

Das folgende Ungetüm ist natürlich viel zu unübersichtlich, obwohl alles richtig läuft.
Mir ist aber unklar, wie ich das vereinfachen kann. (Sehe den Wald vor lauter Bäumen nicht mehr!)
Ich hoffe Ihr könnt mir ein paar Tipps geben!

Code: Alles auswählen

def re_find_nth(pattern, text, index=1, flags=0):
    """Find the n-th match.  Counting starts with zero.
    Default index is 1 == the second match.
    Returns `None` if there are not enough matches.
    """
    for i, match in enumerate(re.finditer(pattern, text, flags)):
        if i == index:
            return match
    return None

# .....
	with open( vplaninausgabemyz ) as f2:
		text = f2.read()

	if re_find_nth(r'SQUARES (\s*-?\d*\.\d*[E]?[+-]?\d?\d?\d?)', text, index=0):
		result_squares = re_find_nth(r'SQUARES (\s*-?\d*\.\d*[E]?[+-]?\d?\d?\d?)', text, index=0)
		if result_squares is not None:
    			squares = result_squares.group(1)

		result_residual = re_find_nth(r'Residual: (-?\d*\.\d*)', text)
		if result_residual is not None:
			residual = result_residual.group(1)

		result_parameter1 = re_find_nth(r'p1: (-?\d*\.?\d*)', text)
		if result_parameter1 is not None:
    			parameter1 = result_parameter1.group(1)
	
		result_parameter2 = re_find_nth(r'p2: (-?\d*\.?\d*)', text)
		if result_parameter2 is not None:
    			parameter2 = result_parameter2.group(1)

		result_parameter3 = re_find_nth(r'p3: (-?\d*\.?\d*)', text)
		if result_parameter3 is not None:
    			parameter3 = result_parameter3.group(1)

		result_parameter4 = re_find_nth(r'p4: (-?\d*\.?\d*)', text)
		if result_parameter4 is not None:
    			parameter4 = result_parameter4.group(1)

		result_parameter5 = re_find_nth(r'p5: (-?\d*\.?\d*)', text)
		if result_parameter5 is not None:
    			parameter5 = result_parameter5.group(1)

		parameterliste = parameter1, parameter2, parameter3, parameter4, parameter5

		with open( pardateineu, 'a') as datendatei:
			for p in parameterliste:
				datendatei.write("  %.7f"%(string.atof(p),))
			datendatei.write("  %5d  %.1f  %.1f  %10s  %25s  "%(lfd, eps, sigma, residual, squares))	
			datendatei.write("\n")

	elif re_find_nth(r'Residual: (-?\d*\.\d*)', text):
		result_residual = re_find_nth(r'Residual: (-?\d*\.\d*)', text)
		if result_residual is not None:
			residual = result_residual.group(1)

		result_parameter1 = re_find_nth(r'p1: (-?\d*\.?\d*)', text)
		if result_parameter1 is not None:
    			parameter1 = result_parameter1.group(1)
	
		result_parameter2 = re_find_nth(r'p2: (-?\d*\.?\d*)', text)
		if result_parameter2 is not None:
    			parameter2 = result_parameter2.group(1)

		result_parameter3 = re_find_nth(r'p3: (-?\d*\.?\d*)', text)
		if result_parameter3 is not None:
    			parameter3 = result_parameter3.group(1)

		result_parameter4 = re_find_nth(r'p4: (-?\d*\.?\d*)', text)
		if result_parameter4 is not None:
    			parameter4 = result_parameter4.group(1)

		result_parameter5 = re_find_nth(r'p5: (-?\d*\.?\d*)', text)
		if result_parameter5 is not None:
    			parameter5 = result_parameter5.group(1)

		parameterliste = parameter1, parameter2, parameter3, parameter4, parameter5
	
		with open( pardateineu, 'a') as datendatei:
			for p in parameterliste:
				datendatei.write("  %.7f"%(string.atof(p),))
			datendatei.write("  %5d  %.1f  %.1f  %10s  "%(lfd, eps, sigma, residual))	
			datendatei.write("\n")

	elif re_find_nth('No corrector convergence', text, index=0):
		convergence = re_find_nth('No corrector convergence', text, index=0).group()

		with open( pardateineu, 'a') as datei:
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler
		
		with open( errormessmyz, 'a') as errordatei:
			errordatei.write("%5d  %.2f  %.2f  "%(lfd, eps, sigma))			
			errordatei.write("No corrector convergence")
			errordatei.write("\n")

	elif re_find_nth('divergence', text, index=0):
		divergence = re_find_nth('divergence', text, index=0).group()

		with open( pardateineu, 'a') as datei:
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler
		
		with open( errormessmyz, 'a') as errordatei:
			errordatei.write("%5d  %.2f  %.2f"%(lfd, eps, sigma))			
			errordatei.write("divergence")
			for a in parameterliste:
				errordatei.write("%.7f  "%(string.atof(a),))
			errordatei.write("\n")

	elif re_find_nth('Matrix', text, index=0):
		matrix = re_find_nth('Matrix', text, index=0).group()

		with open( pardateineu, 'a') as datei:
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler

		with open( errormessmyz, 'a') as errordatei:
			errordatei.write("%5d  %.2f  %.2f"%(lfd, eps, sigma))			
			for p in zzkurz:
				errordatei.write("%.12f  "%(string.atof(p),))
			errordatei.write("Matrix nicht voller Spaltenrang")
			errordatei.write("\n")
deets

Die Tipps wurden dir doch alle schon gegeben: hoer mal auf, alle moeglichen Variablen zu deklarieren, sondern benutze Listen. Kapsele sich wiederholende Codebloecke in Funktionen. Benutze Schleifen, um sowas repititives wie "alle moeglichen Varianten von r'pX: (-?\d*\.?\d*)'" zu erzeugen, statt das jedes mal hinzuschreiben.

Dann sollte das ganze schon deutlich zusammenschnurren, und wieder verstaendlicher werden.
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

So viele Wiederholungen sind es aber gar nicht. Stimmt manche Codeblöcke kommen mehrmals vor, aber höchstens zweimal die gleichen, beim Dritten ist wieder eine Kleinigkeit anders und beim Vierten wieder etwas anderes. Dafür eine Funktion schreiben?

Listen statt Variablen benutzen? :?
BlackJack

@kleiner.epsilon: So etwas nach dem folgenden Muster kommt deutlich mehr als 2× vor:

Code: Alles auswählen

                result_residual = re_find_nth(r'Residual: (-?\d*\.\d*)', text)
                if result_residual is not None:
                        residual = result_residual.group(1)
Und auch bei nur zwei Wiederholungen sollte man schon über eine Funktion zumindest nachdenken. Insgesamt sollte man Wiederholungen vermeiden, zum Beispiel auch bei den Daten. Ein regulärer Ausdruck sollte nicht zweimal identisch im Quelltext stehen. Da geht es nicht nur im die Arbeit das zu tippen, sondern auch darum dass es fehleranfällig bei Veränderungen ist. Man muss dann immer aufpassen das man auch wirklich alle Kopien anpasst. Wenn man so etwas als Konstante definiert, reicht eine Änderung an *einer* Stelle aus.

Wenn man sich wiederholende Quelltextmuster hat, dann sollte man immer schauen worin die sich letztendlich unterscheiden, und ob man das nicht mit Schleifen und/oder Funktionen kürzer und übersichtlicher hin bekommt. Du müsstest mal in Deinem Editor die Tastenkombination für kopieren und einfügen für eine Weile deaktivieren.

Und auch bei Sachen die nur einmal im Quelltext vorkommen, kann man Funktionen schreiben. Ein Grund für das nicht mehr so leicht überblicken können, ist ja die Menge an Anweisungen die man da im Blick haben muss. Wenn man das in kleinere, verständlichere Häppchen aufteilt, die für sich verständlich sind, steigt man auch durch das Gesamtwerk einfacher durch.

Man könnte zum Beispiel die einzelnen Varianten die Du in der Beschreibung im Beitrag durchnummeriert hast jeweils in eine Funktion stecken und dann über eine Liste mit Paaren aus regulärem Ausdruck und der dazugehörigen Funktion iterieren. Beim ersten Treffer ruft man die Funktion mit dem Match-Objekt auf und beendet die Schleife.

Der Quelltext passt übrigens nicht zur Beschreibung. Es gibt in Deiner Beschreibung 4 Punkte aber 5 sich ausschliessende Zweige im Quelltext!? Wenn 'divergence' vorkommt, schreibst Du zum Beispiel nicht wie unter 2. beschrieben die Parameter in eine Datei.

Eine Liste wäre anstelle von `parameter1` bis `parameter5` eine gute Idee.
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@kleiner.epsilon:

`string.atof()` ist übelst antik und wurde in Python 3 auch rausgeschmissen. Ich glaube, man hat dir bereits an anderer Stelle schon gesagt, dass man stattdessen die Builtin-Funktion `float()` verwenden soll. Wäre wohl nicht schlecht, wenn du das in Zukunft auch umsetzt. ;)

Ich mache mir ja ehrlich gesagt ein bißchen Sorgen darüber, woher du deine Kenntnisse beziehst. An der Stelle mal ein Verweis auf den Modulindex in der offiziellen Doku.
Antworten