Erstellen eines "Übersetzers" für Studienarbeit

Du hast eine Idee für ein Projekt?
Antworten
Tom_S
User
Beiträge: 5
Registriert: Freitag 22. Januar 2016, 13:02

Hallo Community,

persönlich bin ich Maschinenbau-Student und völlig unerfahren in Bezug auf die Programmierung.
Im Umfang einer Studienarbeit soll ich nun ein Tool erstellen, welches FE-Decks "übersetzt". Genauer gesagt soll diese Übersetzung zwischen zwei verschiedenen Solver-Typen stattfinden und sich auf die FE-Relavanten Daten beschränken (Knoten, Elemente, Materialien).

Nun habe ich leider keinen Schimmer mit welchen Befehlen ich dies mit Python erziele.
Bisher habe ich ein paar Zeilen geschrieben, welche ein bestehendes File öffnen (zu übersetzendes File) und ein frisches File erstellen (in diesem landet die "Übersetzung").

Knoten sind in diesen Dateien durch X/Y/Z-Koordinaten definiert. Nun soll das Tool Schlagwörter finden und anschließend die relevanten Variablen in einer Matrix ablegen, um anschließend im neuen File die Übersetzung zu platzieren und den Inhalt der Matrix richtig zu positionieren.

Beispiel: Tool findet Schlagwort "Node". Tool speichert die dahinter befindlichen Koordinaten in einer Matrix. Tool schreibt "Grid" in neues File und platziert Koordinaten aus Matrix korrekt dahinter.

Ich habe es auch bereits geschafft, dass mein Tool das Schlagwort "Node" findet und zu "Grid" abändert. Wie ich das mit der Matrix geregelt bekomme, ist mir jedoch schleierhaft.

Für Anregungen, Ideen, Tipps oder sogar eine grobe Programmstruktur wäre ich ausgesprochen dankbar.

Grüße
Tom
BlackJack

@Tom_S: Wirklich konkret kann man dazu ja nichts sagen, zumindest nicht wenn man nicht weiss was „FE-Decks“ sind und was die ganzen Begriffe die Du verwendest, in Deiner Problemdomäne bedeuten.

Allgemein: Zerlege Dein Problem in Teilprobleme, und die wiederum in kleinere Teilprobleme, solange bis die Teilprobleme so klein sind, dass man sie mit ein paar Zeilen Code lösen kann. Teste solche Teillösungen und mach erst mit der nächsten weiter bis die Teillösung das tut was sie soll. Ein übliche grobe Trennung ist Eingabe, Verarbeitung, Ausgabe. Löse diese Teile getrennt voneinander.

Die wichtigsten Richtlinien zum sauberen Programmieren, so dass auch andere den Code verstehen (und man selbst wenn man sich das ein paar Monate nicht mehr angeschaut hat):

Auf Modulebene gehören nur Definitionen von Konstanten, Funktionen, und Klassen. Keine Variablen! Funktionen und Methoden greifen nur auf Werte (ausser Konstanten) zu die als Argumente übergeben wurden, und Ergebnisse verlassen eine Funktion als Rückgabewert.

Gute Namen wählen, die beschreiben was der dahinterstehende Wert im Kontext des Programms bedeutet. Wenn man Kommentieren muss was ein Name bedeutet, ist der Name meistens nicht gut genug. Wenn man keinen guten Namen für einen Wert findet, hat man oft selber das Problem nicht ausreichend verstanden, oder bei zusammengesetzten Werten zu viel oder unpassende Werte zusammengefasst.

Kommentare sollten nicht beschreiben *was* der Code macht, denn das kann man ja schon am Code selbst ablesen, sondern *warum* er das so macht, sofern das aus dem Code nicht bereits offensichtlich ist.

Style Guide for Python Code lesen und beherzigen.
Tom_S
User
Beiträge: 5
Registriert: Freitag 22. Januar 2016, 13:02

Vielen Dank Blackjack, du hast mir mit deiner Antwort das Grundprinzip der Programmierung definitiv nähergebracht.

Deiner Empfehlung, das Problem in Teilprobleme zu unterteilen und diese Schritt für Schritt zu bearbeiten, bin ich nachgegangen. Auf diese Weise habe ich auch bereits einige Zeilen funktionierenden Code "aufs papier" gebracht.

Mir fehlen leider trotzdem noch Kenntnisse, um mein Tool im vollen Funktionsumfang umsetzen zu können.
Eventuell kannst du, oder jemand anderes, mir bei folgender Aufgabe helfen.

Folgende Zeilen habe ich geschrieben:

Code: Alles auswählen

while i<=10000000:
    line=ori.readline()
    if line.find("NODE  /")>=0:
        y=y+1
        print(y)
        new.write(str("GRID\n"))
    elif line.find("SHELL /")>=0:
        x=x+1
        print(x)
        new.write(str("CQUAD4\n"))
    i +=1
Zuvor habe ich zwei Files eingelesen. In "ori" verfügt mein Tool über Lese- und in "new" über Schreibrechte.
Wenn er "NODE /" in ori findet, schreibt er "GRID" in new. Das gleiche geschieht mit "SHELL /" und "CQUAD4".

Nun befinden sich jedoch im ori-file hiner "NODE /" und "SHELL /" Koordinaten, welche ebenfalls übernommen werden müssen.

Das sieht dann so aus:
- In ori -> NODE / X Y Z
- In new -> GRID XYZ

Das Tool muss die Koordinaten also zwischenspeichern und nach der Übersetzung neu positionieren, jedoch ohne Leertrennung.
Ich dachte mir, dass dies gut über einen array gelöst werden könnte. Ich würde also gerne sagen: "Koordinate X, Y und Z in array speichern und nach der Übersetzung an bestimmter Stelle platzieren.

Wie kann ich das in meinem Code einbinden? :K

Vielen Dank für die Hilfe.

Grüße :mrgreen:
Zuletzt geändert von Anonymous am Mittwoch 27. Januar 2016, 09:31, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tom_S: wenn die Übersetzung Zeilenweise erfolgt brauchst Du ja nichts Zwischenzuspeichern. Geht es hier jetzt wirklich um Koordinaten, also Zahlen oder um die Zeichen X, Y und Z? Im ersten Fall verstehe ich das "ohne Leerzeichen" nicht, im zweiten die Schwierigkeit nicht, da es sich um einen immer gleichaussehenden String handelt.

Zum Code: statt einer while-Schleife solltest Du eine for-Schleife nehmen, statt "find" "in" oder gleich startswith, wenn der String am Zeilenanfang steht. Statt x und y sinnvolle Namen:

Code: Alles auswählen

for line in ori:
    if line.startswith("NODE /"):
        node_count += 1
        new.write("GRID\n")
    elif line.startswith("SHELL /"):
        shell_count += 1
        new.write("CQUAD4\n")
Tom_S
User
Beiträge: 5
Registriert: Freitag 22. Januar 2016, 13:02

@Sirius3

Sehr cool, vielen Dank!

Leider funktioniert das ganze mit deinem angeführten Code leider noch nicht. So tauscht er mir zwar das Schlagwort aus, aber die Koordinaten fehlen weiterhin.

Es handelt sich um X-,Y- und Z-Koordinaten, also Zahlenwerte.

Zu dem Punkt mit den Leerzeichen:
Im zu übersetzenden Format sieht das z.B. so aus: NODE / 100.00 200.00 300.00
Im Zielformat dann so: GRID 100.00200.00300.00
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tom_S: das GRID-Format ist also unlesbar. Zum Vorgehen: Du mußt die Zeile mit NODE in ihre Einzelteile aufspalten (str.split) und die Zahlen im gewünschten Ausgabeformat formatieren (str.format).
Tom_S
User
Beiträge: 5
Registriert: Freitag 22. Januar 2016, 13:02

Hey Leute,

mein Übersetzer erfüllt inzwischen die geforderten Funktionen was das finden von Schlagwörtern und austauschen dieser betrifft.

Nun habe ich den Code wie folgt aufgebaut:

Tool findet Schlagwort
Zeile in Einzelteile aufteilen
Einzelteilen Namen zuweisen
Einzelteile richtig angeordnet in neue Datei schreiben

Tool findet nächstes Schlagwort
(Erneutes vorgehen wie in Schleife zuvor..)


Nun wäre es jedoch selbstverständlich sinnvoller, den Einlese- und Schreibteil voneinander zu trennen.
Wie kann ich es realisieren, dass die Schleifen zum einlesen durchlaufen und danach sämtliche neue Zeilen geschrieben werden? :K


Grüße
Tom
BlackJack

@Tom_S: Iteratoren, Generatorfunktionen und -ausdrücke, und das `itertools`-Modul kann bei solchen Aufteilungen helfen. Wenn die Eingabedaten beispielsweise Zeilenweise verarbeitet werden können, kann man eine Funktion schreiben die einen Dateinamen bekommt und einen Iterator/Generator über die Zeilen der Datei liefert.

Dann kann man eine Funktion schreiben, die eine Zeile bekommt und verarbeitet und das Ergebnis zurück gibt.

Diese Funktion kann man dann mit `itertools.imap()` (oder `map()` in Python 3) auf das Ergebnis der ersten Funktion anwenden und erhält einen Iterator über die verarbeiteten Zeilen.

Dann braucht man nur noch eine Funktion die diesen Iterator und einen Dateinamen entgegen nimmt und die Zeilen in eine Datei schreibt.

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
from itertools import imap


def iter_lines(filename):
    with open(filename) as lines:
        for line in lines:
            yield line


def convert_line(line):
    return line  # Do something with line here if necessary.


def save_lines(filename, lines):
    with open(filename, 'w') as out_file:
        out_file.writelines(lines)
        

def main():
    save_lines('output.txt', imap(convert_line, iter_lines('input.txt')))


if __name__ == '__main__':
    main()
Tom_S
User
Beiträge: 5
Registriert: Freitag 22. Januar 2016, 13:02

Vielen Dank!!

Ich frage mich aktuell wie ich es ermöglichen kann, dass mein Tool aus einer bestimmten Anzahl Zeilen nach einem Schlagwort liest.

Ich suche nach Wort XY. Danach soll aus zwei Zeilen später ein bestimmter Bereich gelesen werden.

Schaut also so aus:

Code: Alles auswählen

if line.startswith("XY"):
	lines=ori.readline()
	* Jetzt müsste ich ihm sagen "lies zwei Zeilen später"*
	ABC = line[0:10]
Womit kann ich sowas realisieren?

Grüße
BlackJack

@Tom_S: Du meinst lies eine Zeile später, denn eine hast Du ja bereits weiter gelesen. Diese einzelne Zeile bindest Du an den Namen `lines`, das ist irreführend. Und statt `readline()` würde ich eher mit der `next()`-Funktion arbeiten, denn wenn man in der Funktion die Eingabe durchgängig als allgemeines über Zeilen iterierbares Objekt behandelt, kann man da auch andere Sachen als Dateiobjekte übergeben. Beispielsweise Iteratoren die in einem Arbeitsschritt davor schon irgendwie die Zeilen behandeln (Ändern, künstlich Daten einfügen, ausfiltern), oder Listen für automatisiserte Tests.
Antworten