Matrizen aus Datei parsen mit Variablen



  • Hallo zusammen,

    für ein Projekt mit Matrizenrechnung muss ich einige Matrizen aus einer Datei einlesen können.
    Außerdem ist es wichtig, dass auch variablen und arithmetische Ausdrücke vorkommen können.
    Hier mal eine Beispieldatei:

    %list of variables
    w_f = 0; %kommentar...
    w_s = 1e10;
    dt = 0.123123;

    A = [1,2,3;4,5,6; w_f*w_s*dt];

    asd = 2.34; % variablen können auch mittendrin deklariert werden

    B = [1,2;3,4;5,6.243];

    Das Format der Datei kann ich selbst festlegen, es sollte aber möglichst benutzerfreundlich sein.
    Variablen sollen (erstmal) nur konstante double-Werte sein können, sie dürfen nicht durch weitere variablen berefchnet werden (um das ganze einfach zu halten).
    Da es bei diesem Teilprojekt um eine Portierung von Matlab nach C++ geht, habe ich eine Matlab-ähnliche Syntax gewählt.

    Ich hatte jetzt vor, dass ganze in mehereren Schritten zu parsen:
    Im 1. Schritt werden (vermutlich mithilfe von Regex) Kommentare entfernt und dann splitte ich alles was übrig bleibt am Semikolon und erhalte einige strings, die ich dann nacheinander abarbeite.

    Bei der Verarbeitung eines String ersetze ich zuerst alle variablen durch die jeweiligen Werte (hatte vor, dass auch irgendwie mit regex zu machen, wie genau muss ich noch schaun).
    Danach überprüf ich, ob eckige Klammern vorhanden sind.
    Wenn ich eckige Klammern finde, weiß ich, dass es sich um eine Matrix handelt, wenn nicht ist es eine Variable, die in eine map die von string nach double mappt aufgenommen wird.
    Handelt es sich um eine Matrix, dann splitte ich am semikolon, um die einzelnen zeilen zu erhalten und danach für jede Zeile nochmal am komma, um einzelne Ausdrücke zu erhalten.
    Dann werden erstmal die dimensionen auf konsistenz geprüft und dann die einzelnen ausdrücke ausgewertet (wie bei einem taschenrechner-programm).
    Zum parsen von diesen Ausdrücken die dann rauskommen habe ich schon gutes Material aus einem Buch.

    Soweit der Plan 🙂

    Mir fällt gerade noch auf, dass ich das Semikolon für 2 verschiedene Zwecke missbraucht hab, 1 mal zum Markieren, dass eine Anweisung/Variablendefinition zuende ist und einmal zum markieren vom ende einer spalte. Ich werd eins von beiden dann wohl am besten erstezen, nur habe ich noch keine "gutaussehende" alternative gefunden.

    Ich wollte fragen, ob ihr dazu noch tipps oder Verbesserungsvorschläge habt.
    Da ich das Format selbst wählen kann, sind vielleicht noch Vereinfachungen möglich, die mir entgangen sind.

    Vielen Dank schonmal für eure Hilfe!



  • ersetze einfach die Zeichen ";\n" durch "\n". Weil es in MATLAB sowieso immer die letzte Anweisung in einer Zeile ist



  • Dann sind mehrere Anweisungen pro Zeile und Anweisungen über mehrere Zeilen aber nicht mehr möglich, oder sehe ich das falsch?



  • Q schrieb:

    Dann sind mehrere Anweisungen pro Zeile und Anweisungen über mehrere Zeilen aber nicht mehr möglich, oder sehe ich das falsch?

    Lesbarer Code sollte sowieso nicht mehr als eine Anweisung je Zeile haben.

    Anweisungen über mehrere Zeilen gehen nicht, es sei denn du verwendest den ... Operator und den kannst du ja auch herausfiltern.



  • Ich geb dir zwei Tipps.

    1. Du solltest das nicht irgendwie zusammenfrickeln, sondern dich erstmal zum Thema Syntaxanalyse, Parsing, Grammatiken usw. schlau machen.

    2. Benutze keine allzustark an Matlab angelehnte Syntax. Denn die User werden irgendwann fordern, dass du mehr und mehr Sprachelemente von Matlab unterstützt. Dabei wolltest du eigentlich nur ein Datenformat ... Außerdem ist die Matlab-Grammatik grottig zu parsen (die ist anscheinend entwickelt worden, ohne meinen Tipp 1 zu beherzigen, was ironischerweise bedeuten kann, dass du mit Handgefrickel doch am schnellsten zum Ziel kommst 😉 )



  • Ich habe schon was zu Grammatiken gelesen, damit habe ich vor die einzelnen ausdrücke zu parsen nachdem diverse splits und ähnliches angewendet sind. Alles andere lässt sich meiner meinung nach aber recht gut mit handgefrickel machen 😃
    Ich hätte aber schon interesse mir die Themen Syntaxanalyse & co mal näher anzusehen, weiß nur nicht genau ob ich da so bald zu komme.
    Kennst du denn was gutes zum lesen (am besten online)?

    Und das immer mehr von Matlab gefordert wird glaube ich eher nicht und wenn doch habe ich kein Problem damit, da ich die Sache mit dem Parsing und co interessant finde und dann noch mehr Zeit darauf verwenden kann, mir das anzugucken.



  • Hallo Q,

    schaue Dir mal diesen Thread (Zeilen einlesen, Parameter speichern und später verwenden) an. Dort sind bereits wesentliche Elemente, von dem was Du benötigst, realisiert.

    Gruß
    Werner



  • Hallo Werner, danke für den Link. Leider finde ich das was dort angewendet wird nicht sonderlich verständlich und ich wollte eigentlich möglichst viel selbst implementieren um dabei zu lernen.

    Ich habe gerade eine TokenStream-Klasse geschrieben, die nach allen bisherigen Tests funktioniert.

    Jetzt entwerfe ich gerade eine Ausdrucks-Grammatik, allerdings bin ich mir dabei ziemlich unsicher, weil ich sowas noch nie gemacht hab.
    Hier ist mein derzeitiger Entwurf:

    Definition:
       Variable
       Matrix
    Variable:
       Variable-name "=" Number ";"
    Matrix:
       Variable-name "=" Matrix-Definition ";"
    Matrix-Definition:
       "[" Rows "]"
    Rows:
       Row    
       Rows ";" Row
    Row:
       Expression
       Row "," Expression
    Variable-name:
       string-literal containing only alphanumerical characters and underscores
    Expression:
       Term
       Expression "+" Term
       Expression "-" Term
    Term:
       Primary
       Term "*" Primary
       Term "/" Primary
       "-" Primary
       "+" Primary
    Primary:
       Number
       "(" Expression ")"
    Number:
       floating-point-literal
    


  • Was mir noch aufgefallen ist: Wenn ich den Token-Stream verwende, verliere ich Informationen über Zeilennummern und kann bei Fehlermeldungen nicht mehr auf eine solche verweisen...

    Hat jemand eine Idee, wie ich das ändern kann? Ich könnte bei jedem Token eine Zeilennummer mitspeichern, allerdings würde das einlesen wesentlich schwieriger werden, wenn ich dauernd auf newline prüfen muss, denke ich...

    Edit: Habs mit dem linecount jetzt doch hinbekommen.



  • Da du hier ja schon fast eine EBNF hast, könntest du dir boost::spirit mal ansehen.



  • Danke für den Tipp mit boost.
    Allerdings will das ganze ja erstmal versuchen selbst zu implementieren um mal zu lernen wie das so funktioniert. Wenn ich dann irgenwann etwas Erfahrung habe, dann schaue ich mir boost::spirit an.

    Hier gerade nochmal eine Frage:
    Ich muss rausfinden, ob ich am Ende der Datei bin. Geht das wirklich nur so umständlich, oder gibts da nen besseren weg?

    bool TokenStream::AtEnd()
    {
    	if(!buffer_.empty())
    	{
    		return false;
    	}
    	if(ifs_.eof())
    	{
    		return true;
    	}
    	char ch;
    	ifs_ >> ch;
    	if(ifs_.eof())
    	{
    		return true;
    	}
    	ifs_.putback(ch);
    	return false;
    }
    

    Und dann noch eine Frage zu putback: Kann ich nur 1 char zurücktun, oder funktioniert das auch wenn ich mehrere hinteeinander zurücktue?


Anmelden zum Antworten