Seite 1 von 2

Eigener Parser will nicht so wie ich

Verfasst: Samstag 19. Dezember 2009, 12:57
von theliquidwave
Hi.
Ich habe schon des öfteren Parser für Dateien geschrieben, deren Ebenen aber begrenzt waren (Beispiel: INI -> begrenzt, XML -> unbegrenzt).
Nun wollte ich für mein neues Projekt auch einen Parser schreiben, der unbegrenzt viele Ebenen unterstützt, das ganze ist jedoch schwieriger als zuvor vermutet.

Diesen Code hier habe ich bereits fabriziert:

Code: Alles auswählen

self.data = {}

#...

def isNextLineSectionStart(index):
	if len(lines) > index + 1:
		return lines[index + 1].startswith("{")
	
	return False

fileobj = open(path, "r")
lines = [line.strip().rstrip().split("//")[0] for line in filter(lambda line: len(line.strip().rstrip()) and not line.strip().startswith("//"), fileobj)]
fileobj.close()

current = self.data
previous = [self.data]

for index, line in enumerate(lines):
	if isNextLineSectionStart(index):
		previous.append(current)
		current = current[line] = {}
		
		continue
	
	if line.startswith("}"):
		current = previous.pop()
		
		continue
	
	if line.count(" "):
		char = line.find(" ")
		value = line[char + 1:]
		current[line[:char]] = (value[value.find("\"") + 1:value.rfind("\"")] if value.count("\"") else value)

self.data = current
Das ganze soll für folgendes Format funktionieren:

Code: Alles auswählen

start
{
	position1 "-1022.963745,793.409607,8.966581"
	position2 "-1024.971558,70.542549,416.005066"
	name "Start"
	reset 1
	time 0.0
	active 1
	give
	{
		item "flashlight"
		weapon "rpg"
		ammo
		{
			amount 20
			type "rocket"
		}
	}
}

bla
{
	# ...
}
Das ganze funktioniert anscheinend auch, debugging-Ausgaben zeigen genau das an, was es soll (z.B. Zeile 33), aber am Ende ist ``current`` bzw. ``self.data`` leer. Ich habe schon verdammt viel herumprobiert, aber ich kriege das einfach nicht hin.

Ich könnte es auch auf eine Ebene begrenzen, aber das ist
a) nicht der Sinn da ich die Konfiguration dann umschreiben müsste
b) doof weil ich es dann nie verstehen würde

Hoffentlich könnt ihr mir dazu Tipps geben und auch sagen, wieso das ganze so nicht funktioniert. Ich möchte es nämlich nicht nur fertig haben sondern auch verstehen :)

Danke im voraus an alle. Und bitte keine Ratschläge für irgendwelche XML-Parser oder so - damit habe ich bereits gearbeitet aber ich möchte es einfach mal selber probieren ;)

Edit: Mir ist gerade noch eingefallen, dass ich auch "Probleme" beim erkennen bzw. splitten der Daten habe. Bisher kann man nur

Code: Alles auswählen

name "wert"
schreiben - 2 oder mehr Leerzeichen und/oder Tabs kann man nicht benutzen da es dann nicht mehr funktionieren würde. Wie kann man das lösen? (Betrifft Zeile 30 und 31)

Gruß

Verfasst: Sonntag 20. Dezember 2009, 12:40
von audax
Beschränke es auf eine Ebene und rufe dich selbst einfach rekursiv auf :)

Verfasst: Sonntag 20. Dezember 2009, 13:11
von theliquidwave
Hi.
Der Kram mit rekursiv ist mir irgendwie zu kompliziert. Ich habs versucht, aber das endete im Chaos :lol:
Habe es nun doch lösen können. Auch das Problem mit dem Leerzeichen ist behoben, wenn auch hässlich.

http://pastebin.com/d7ed2c028

Gruß

Verfasst: Sonntag 20. Dezember 2009, 17:16
von Defnull
Ist das Datenformat vor gegeben? Wenn nicht, würde ich dir dringend raten, ein existierendes Format (z.B. JSON oder XML) zu nehmen.

Verfasst: Sonntag 20. Dezember 2009, 18:31
von theliquidwave
Das Datenformat ist nicht vorgegeben aber bei Source-Engine Gameservern durch die KeyValues von VALVe sehr üblich, deshalb wollte ich das Format immitieren.

http://developer.valvesoftware.com/wiki/KeyValues

Gruß

Verfasst: Sonntag 20. Dezember 2009, 22:41
von sma
Siehe http://vimeo.com/8297457 :)

Ich habe mir eine Screencasting-Software gekauft und das war mein erster Versuch. Vielleicht hilft's ja aber trotzdem...

Stefan

Verfasst: Sonntag 20. Dezember 2009, 22:49
von theliquidwave
lol :D
Leider bist du verdammt leise, muss die Boxen hochdrehen - dann geht's.

Edit: Hab's mir mal reingezogen. Viel einfacher als mein Code rumgewurschtel :lol: Weiter so ;)

Edit2: Wenn ich mal fragen darf - was ist das für 'ne nette Testsuite die du da hast? Vermutlich ist das Mac oder Linux - gibt es vergleichbares für Win?

Gruß

Verfasst: Sonntag 20. Dezember 2009, 23:09
von jbs
sma benutzt Mac.

Respekt, die Stimme ist deutlich und alles verständlich.

Verfasst: Sonntag 20. Dezember 2009, 23:28
von Leonidas
jbs hat geschrieben:Respekt, die Stimme ist deutlich und alles verständlich.
Ja, ist mir auch positiv aufgefallen. sma, hast du das nachsynchronisiert oder so in einem Durchlauf gemacht?

Verfasst: Sonntag 20. Dezember 2009, 23:48
von ms4py
Leonidas hat geschrieben:
jbs hat geschrieben:Respekt, die Stimme ist deutlich und alles verständlich.
Ja, ist mir auch positiv aufgefallen. sma, hast du das nachsynchronisiert oder so in einem Durchlauf gemacht?
Aufgrund seines Kommentars ist das vermutlich nicht nachsynchronisiert ;)
Dies ist mein erstes Video und ich fand es verdammt schwer, gleichzeitig zu tippen und dabei zu reden.

Verfasst: Sonntag 20. Dezember 2009, 23:55
von sma
Ja, ich benutze einen Mac. Ich glaube auch nicht, das ich daraus in Vergangenheit wirklich ein Geheimnis gemacht habe ;) Die "Testsuite" ist einfach die "Run Script"-Funktion von TextMate, dem Texteditor, den ich für Python benutze. Das ich leise bin, ist mir leider auch aufgefallen - allerdings erst in der Vimeo-Version. Man kann da auch noch die Original-Quicktime-Datei laden. Das Video habe ich in einem Durchlauf aufgezeichnet, allerdings seht ihr da den dritten Versuch.

Stefan

Verfasst: Montag 21. Dezember 2009, 00:17
von Leonidas
sma hat geschrieben:Man kann da auch noch die Original-Quicktime-Datei laden. Das Video habe ich in einem Durchlauf aufgezeichnet, allerdings seht ihr da den dritten Versuch.
Hab ich auch gemacht (Chromium spielt die sogar direkt ab) und mich gewundert was die anderen mit "zu leise" meinten.

@ice2k3: Ooops.

Verfasst: Montag 21. Dezember 2009, 09:01
von /me
sma hat geschrieben:Siehe http://vimeo.com/8297457 :)
Ganz großes Kino!

Schöne Lösung, schöner Screencast.

Verfasst: Montag 21. Dezember 2009, 09:37
von Defnull
sma, du hast nen neuen Fan :D Mehr davon :)

Verfasst: Montag 21. Dezember 2009, 14:20
von Dav1d
Ein paar Sachen, diem mir aufgefallen sind

wieso verwendest du in

Code: Alles auswählen

print parse(iter(example.splitlines()))
das iter()?
Splitlines gibt doch eine Liste zurück

Zeile 27 und 28 könntest du auf

Code: Alles auswählen

key, value = line.split(None, 1)
kürzen

Das Video ist wirklich gut gelungen

Verfasst: Montag 21. Dezember 2009, 16:15
von martin101986
Hallo,
Dav1d hat geschrieben:Ein paar Sachen, diem mir aufgefallen sind

wieso verwendest du in

Code: Alles auswählen

print parse(iter(example.splitlines()))
das iter()?
Splitlines gibt doch eine Liste zurück
Das iter() hat hier schon seinen Sinn. Wenn du der Funktion parse nur eine Liste übergibst, erreichst du die maximale Rekursionstiefe da du innerhalb der von parse die Funktion parse mit der selben Liste wieder aufruft und diese wieder von vorne abgearbeitet wird und dann wieder parse aufruft usw, es wird niemals die Abbruchbedingung erfüllt.

Verwendest du hingegen einen Iterator wird die next()-Methode des Iterators aufgerufen. Wenn du innerhalb von parse erneut parse aufrufst weiß der Iterator an welcher Stelle er stehen geblieben ist und gibt den nächsten Wert zurück.

Hoffe das hilft dir weiter.

Grüße Martin

Verfasst: Montag 21. Dezember 2009, 16:57
von Dav1d
Danke,

das habe ich total übersehen

Verfasst: Montag 21. Dezember 2009, 17:17
von fred.reichbier
Ich kann mich nur anschließen. Sehr schönes Video! :)

Verfasst: Sonntag 3. Januar 2010, 03:01
von Hyperion
Ich fand das Video (und die anderen!) auch sehr gut gemacht. Daher konnte ich nicht umhin, das ganze ein wenig zu erweitern und zu ergänzen. Das Ergebnis findet man hier: Source

Ich war so frei smas Funtkion ein wenig aufzubohren - zumindest habe ich mal vermutet, dass auch Interesse am Parsen der Koordinaten bestehen könnte.

Verfasst: Sonntag 3. Januar 2010, 11:30
von sma
Hyperion hat geschrieben:Ich war so frei smas Funtkion ein wenig aufzubohren - zumindest habe ich mal vermutet, dass auch Interesse am Parsen der Koordinaten bestehen könnte.
Deine Koordinaten-Erkennung würde den String "Web 2.0" zu [2.0] machen. Ist das beabsichtigt? Wenn du Koordinaten erkennen willst, würde ich auf einen String der Form \d+\.\d+,\d+\.\d+,\d+\.\d+ achten und nur diesen umwandeln - wenn überhaupt, da das schon sehr speziell ist und dem Parser die Allgemeingültigkeit nimmt.

Stefan