Datei zeilenweise parsen (Suchmuster)
-
Hallo,
ich habe schon im Netz gesucht, doch nirgends eine passende Antwort gefunden.
Ich möchte eine Datei zeilenweise parsen, das mache ich momentan mit fgets().
In jeder Zeile steht ein bestimmtes Muster, z.B.LOAD <filename> AS <table>
INSERT INTO <table> <value1>, <value2>, <value2>, ...Der String in den Spitzen klammern soll gespeichert werden, das LOAD ... ist nur dafür da, um herauszufinden, welche Operation durchgeführt werden soll. Jede Zeile soll natürlich auf ihre
Korrektheit geprüft werden.Ich weiss nicht, wie ich das am Besten parse, ein Ansatz war:
if (sscanf(line, "LOAD %s AS %s", filename, table) == 2) {
// mach was
}
Zwar funktioniert das so halb, aber nicht so wie es sein muss. Wenn ich an dem AS etwas anhänge (ASAS), dann interpretiert er das immer noch alls korrekt.Wie kann man da am besten vorgehen?
-
Naja, gesetzt den Fall du hast eine komplette Zeile ausgelesen, könntest du z.b. mit einem Kellerautomaten parsen...
In deinem Fall würde ich dir aber raten, da deine Zeile in token zu zerlegen, und zwar immer genau an den Leerzeichen. Dann kannst du dir die Schlüsselwörter definieren und die Teile der Zeile jeweils zuweisen, ob es ein Schlüsselwort oder ein Wert, etc. ist. (Und je nachdem in einen bestimmten Zustand wechseln)
Damit solltest du ganz gut die Syntax parsen können.
-
Du kannst auch einfach einen kleinen Lexer zusammen bauen
der Zeichenweise aus deine Datei einliest. Wenn du damit fertig bist kannst relativ einfach deine Grammatik parsen sollte in unter 1000 Zeilen Code fertig sein.Ich glaube unter den Artikeln hat jemand vorgestellt wie man einen Parser baut der auf den Rekursiven abstieg beruht!
-
Cefour mein diesen hier: http://www.c-plusplus.net/forum/268247 (ab Punkt 6)
wobei die Idee dieselbe ist, die ich umständlich zu erklären versucht hab. Deine SQL-ähnliche "Eingabesprache" sieht auch so aus, als würde so ein kleiner Lexer da ganz gut arbeiten.
-
Meinte ich ja auch ein kleiner Lexer wäre wohl das sinnvollste !
-
Du bist noch nicht in die Tiefen von *scanf vorgedrungen, das Thema Whitespaces im Format- und/oder Parsestring ist etwas diffizil, einfach für den Anfang wäre z.B. (wobei die Aktions- und variablen Werte selbst kein Leerzeichen enthalten):
if (sscanf(line, "%s%s%s%s", a,b,c,d) == 4) { if( !strcmp(a,"LOAD") && !strcmp(c,"AS") ) /* machwas mit b und d */ }
-
Danke erstmal für eure Tipps.
Also die verbesserte Variante von Wutz klappt soweit, die Frage ist ob eine solche Vorgehensweise sinnvoll ist oder, wie genannt, ein Lexer besser wäre.
Aber ich denke ein Lexer wäre wirklich das sinnvollste...
-
Also ich habe das jetzt vorerst ohne Lexer realisiert,
sprich mit fgets() zeilenweise eingelesen und mit sscanf die Zeile
überprüft und den jeweils variablen Teil gespeichert. (ähnlich wie Wutz es beschrieben hat).Soweit funktioniert das problemlos, bei allen Fällen. Die Frage ist, ob diese Variante so elegant ist. Diese Frage möchte ich nochmal an euch richten...
ein Scanner + Parser wäre doch evtl. sinnvoller?!
-
Die Frage ist, was du unter Eleganz verstehst und wieviel Arbeit du reinstecken möchtest. Die Interpretation deiner Anweisungen in eine Funktion zu kapseln ist sicher von der Bedienung und zur Fehlersuche/Logging besser, aber dazu bedarf es auch wieder einer neuen Schnittstelle, nämlich die deines neugeschaffenen Interpreters, was wieder zusätzlichen Code mit möglichen Fehlerquellen bedeutet.