[GELÖST] Buchstabenweises kopieren eines Strings?
Übersicht

CO2ehemals "SirMO"Betreff: [GELÖST] Buchstabenweises kopieren eines Strings? |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Hallo,
ich versuche gerade einen XML-Parser zu bauen und stehe gerade ziemlich auf dem Schlauch ![]() Ich lasse eine Zeile aus einer XML-Datei auslesen und möchte diese unterteilen, allerdings soll das nicht statisch sein, also das man später nicht immer genau 1 Leerzeichen zwischen den attributen machen muss, oder das die attribute nicht immer genau in der selben reihenfolge sein müssen. Meine probier-XML-Datei sieht wie folgt aus: Code: [AUSKLAPPEN] <?xml version="1.0" encoding="utf-8" standalone="no" ?>
(leere Strings nicht beachten, werden noch gefüllt <vehicle> <id>$VEH_AMBULANCE$</id> <name>Krankenwagen</name> <model file="mod\ambulance.2dm"/> <motion accelerate="" deccelerate="" maxspeed=""/> <multiplayer active="true"> <seat>6</seat> </multiplayer> <fuel type="2" usage="" capacity="85"/> <engine> <cylinder>6</cylinder> <ps>125</ps> </engine> <coord> <turnpoint x="" y=""/> <exhaustpoint x="" y=""/> </coord> </vehicle> ![]() Und die Funktion die das auslesen soll sieht momentan so aus: BlitzMax: [AUSKLAPPEN] Function ReadVehicleXML(File:String)("Vehicle" ist ein von mir definierter Type ![]() Kurz zur erklärung: Eine Zeile wird ausgelesen und getrimmt. Wenn die ersten zwei zeichen des Strings "<?" sind, nächste Zeile auslesen. Wenn allerdings die ersten 9 Zeichen des Strings "<vehicle>" entsprechen, dann... und ab hier weiß ich nicht weiter. Wie lese ich z.B.: die "motion"-Zeile (in der XML-Datei) aus? Oder wie kann ich einen String solange kopieren, bis der end-Tag kommt (z.B.: bei dem "id"-Tag)? Ich hoffe ihr könnt mir helfen |
||
mfG, CO²
Sprachen: BlitzMax, C, C++, C#, Java Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti |
- Zuletzt bearbeitet von CO2 am Mi, Jan 11, 2012 21:09, insgesamt einmal bearbeitet
![]() |
d-bug |
![]() Antworten mit Zitat ![]() |
---|---|---|
Gaaaaaanz wichtig: Beschäftige dich umgehend mit Slices und dem Typ String im allgemeinen.
Lese dazu bitte die Hilfe von BlitzMax. z.B. Um aus der Zeile den Tag "<Vehicle>" zuverlässig raus zubekommen nutze doch einfach String.replace(" ","") wenn du sicher bist dass es sich nur um Leerzeichen handelt, ansonsten: string[string.find("<")..string.find(">")] ...da fehlt aber noch irgendwo die Korrektur der Position... usw. usw. usw. Mit dem BRL.Retro Modul kommst du bei BlitzMax nicht immer ans Ziel! Außerdem ist es absolut veraltet! ![]() |
||
![]() |
Midimaster |
![]() Antworten mit Zitat ![]() |
---|---|---|
ist natürlich ein nettet Tipp! Berührt aber in keinster Weise seine Frage.
Leider habe ich noch nie eine Parser gecoded, aber ich würde es so anfangen: Sobald der TAG <Vehicle> aufgetaucht ist, kommen ja wahrscheinlich anschließend seine Parameter. Ich würde beim Erscheinen eines bestimmten TAGs einen TYPE für die zu erwartenden Parameter anlegen und anschließend in eine Funktion springennen, um dort die folgenden Zeilen auswerten. Da ja die Reihenfolge nicht zugesichert ist, füllst Du eben immr das Element, das Du gerade zufällig findest. Entscheidendes Zeichen für einen TAG-Beginn ist immer das "<", du trennst den daran hängenden String heraus (bis zum ">") und verzweigst dann in eine entsprechende tiefere Funktion, möglicherweise wieder mit einem neuen TYPE. Dort wird der Inhalt ausgelesen und in den TYPE übertragen. Am Ende überprüft man, ob dieser TAG ordnungsgmäß endet. und gibt den entstandenen TYPE an die höherliegende Funktion zurück. So müßte sich allmählich der Verhicle-TYPE und seine sub-TYPEN füllen. Pseudocode: Code: [AUSKLAPPEN] NextTag$ = FindeTag(RestText$) Select NextTag$ Case "vehicle" Vehicle:VehicleTyp=ZerlegeVehicle() End Select Function ZerlegeVehicle:VehicleTyp() local loc:VehicleTyp local locText$ = SchneideTag("/Id", RestText) NextTag$ = FindeTag(locText$) Select NextTag$ Case "Id" loc.Id=SchneideTag("/Id", locText) Case "name" loc.name=SchneideTag("/name", locText) Case "/verhicle" Return loc End Select End Function wo mehrere Parameter zu erwarten sind zweigst du wieder in eine Sub-Funktion. Hier am Beispiel von "motion": Code: [AUSKLAPPEN] .....
Function ZerlegeVehicle:VehicleTyp() local loc:VehicleTyp local locText$ = SchneideTag("/Id", RestText) NextTag$ = FindeTag(locText$) Select NextTag$ Case "Id" loc.Id=SchneideTag("/Id", locText) Case "motion" loc.motion=ZerlegeMotion(locText) ...... End Function ...... Function ZerlegeMotion:MotionTyp(RestText$) local loc:MotionTyp local locText$ = SchneideTag("/motion", RestText) NextTag$ = FindeTag(locText$) Parameter$ = FindeParameter(RestText$) Select Parameter$ Case "accelerate" loc.Accelerate=WertZu("accelerate=",RestText) Case "maxspeed" loc.MaxSpeed=WertZu("maxspeed=",RestText) Case "/> Return loc End Function Vorsicht: Das ist hier nur Pseudo-Code. Nur ein Entwurf. Bedenke auch ich hab sowas noch nie gemacht, und kann dir keine Garantie geben, dass dies der richtige Weg ist. Der Teufel steckt bei Parsern im Detail! Vor allem ist es wichtig zu erkennen, wann man den gelesenen TAG endgültig aus dem RestText$ entfernt. Die Funktion FindeParameter() soll immer den nächsten Parameter innerhalb von TAG-Grenzen finden, die Funktion SchneideTag() findet immer was zwischen einen Start-Tag und einen End-Tag steht. |
||
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe |
![]() |
ZEVS |
![]() Antworten mit Zitat ![]() |
---|---|---|
Meine Methode für Parser ist ziemlich unübersichtlich, aber schnell und sicher. Du gehst einfach das gesamte Dokument einmal durch, Zeichen für Zeichen und schaust halt, was das bedeuten soll. Lässt sich eigentlich auf alles anwenden, nur halt ist die Schleife ziemlich lang.
Ein Ausschnitt aus meinem XML-Modul: BlitzMax: [AUSKLAPPEN]
Es lässt ein bisschen mehr durchgehen, als es eigentlich dürfte und beherrscht nicht das ganze XML mit CDATA und DTDs, aber mir reicht es. Falls Interesse am Rest-Code besteht, kann ich reinstellen. ZEVS |
||
![]() |
d-bug |
![]() Antworten mit Zitat ![]() |
---|---|---|
Minimaster hat Folgendes geschrieben: ist natürlich ein nettet Tipp! Berührt aber in keinster Weise seine Frage.
Doch, eigentlich schon. Nur sehe ich nicht ein ihm den fertigen Code zu geben. Auf diese weise reicht ihm nämlich mehr oder weniger copy-paste und der Lernfaktor bleibt auf der Strecke. Grüße |
||
![]() |
ZEVS |
![]() Antworten mit Zitat ![]() |
---|---|---|
Es ist kein fertiger Code. Es fehlt nämlich noch das Modul darum. Ohne intensive Auseinandersetzung bekommst du den nicht zum Laufen ![]() Außerdem gibt es wahrscheinlich irgendwo hier oder im englischen Portal einen XML-Reader, den du Copy+Pasten kannst. Ich glaube, FDM hatte sowas bei denem letzten BCC-Beitrag, da kann man auch klauen. Wenn es CO2 darum ginge, dann würde er diesen Thread nicht so eröffnen. Ich bleibe dabei: Wenn Interesse am Rest-Code besteht, stelle ich den rein. ZEVS |
||
![]() |
BladeRunnerModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
ZEVS: Buggies Antwort galt ja nicht Dir, sondern Midimaster. Und ich stimme ihm voll zu: Seine Antwort hat mit der Fragestellung sogar sehr viel zu tun, denn Slices sind ein famoser Weg um Parsing zu betreiben. | ||
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3 Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64 B3D BMax MaxGUI Stolzer Gewinner des BAC#48, #52 & #92 |
CO2ehemals "SirMO" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
So, dann werd ich mal anfangen:
@ d-bug: Ok, hab mir mal eben über google ausspucken lassen, was slices sind. Damit könnte das funktionieren, werde es auf jeden fall mal ausprobieren ![]() @ Midimaster: Ok, mal sehen ob ich das verstanden habe: Ich brauche also einen Vehicle-Type, sowie einen (?) zwei (?) Sub-Type(n). Diese beinhalten dann z.b. die werte der parameter in den Tags, der eine speichert die parameter die zwischen 2 Tags stehen (also z.b.: "<digit>45</digit>"), der andere die, die in einem Tag stehen (z.B.: "<digit amount="45"/>")? Oder wie? @ ZEVS: Zitat: Dokument einmal durch, Zeichen für Zeichen - Das ist das Problem, was ich habe ![]() Mir reichte es, wenn es nur die Parameter aus den Tags auslesen könnte... ![]() |
||
mfG, CO²
Sprachen: BlitzMax, C, C++, C#, Java Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti |
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Mein Tipp: Nimm einfach ein fertiges Modul z.B. Libxml von Brucey und setz deine Zeit für das Spiel ein. | ||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
CO2ehemals "SirMO" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Hallo,
Es hat mir doch keine Ruhe gelassen, also hab ich 2 Funktionen geschrieben. Die eine Ließt Parameter zwischen 2 Tags aus ("<Digit>23</Digit>"), die andere ließt Parameter in einem Tag aus ("<Digit amount="42"/>") - Allerdings macht letztere Probleme: Wenn ich mehr als 1 Parameter in einem Tag auslesen will, kriege ich einen Fehler: "Unhandled Exception: Attempt to index array element beyond array length". Hier mal die Funktion BlitzMax: [AUSKLAPPEN] Function GetParamInTag(Line:String, NumberOfParams:Int, ReadParams:String[]) Hier die Zeile die ausgelesen werden soll Code: [AUSKLAPPEN] <motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/>
Und hier mal der Funktionsaufruf BlitzMax: [AUSKLAPPEN] If(Left(Line, 7) = "<motion") 'Bewegung (Ich weiß: Die Parameter müssen jetzt immer in der gleichen reihenfolge stehen, aber sche** drauf ![]() Markiert wird in der Funktion die Zeile "ReadParams[x] = ParamWithOutZoll[y]"... Ich hoffe ihr könnt mir helfen |
||
mfG, CO²
Sprachen: BlitzMax, C, C++, C#, Java Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti |
![]() |
ToeB |
![]() Antworten mit Zitat ![]() |
---|---|---|
Also ich würde mir ja, anstatt die ganzen Befehle der XML-Datei einzeln abzufragen lieber direkt ein XML-Parser basteln welcher die Datei einließt und die Befehle und ihre Parameter in "Nodes" (Knoten) speichert und dann immer weiter verlinkt. Ich habe mal einen gebastelt, ist schon was länger her, aber vielleicht hilft es dir ja :
BlitzMax: [AUSKLAPPEN]
Hiermit wird also eine Datei eingelesen (OpenXML). Diese wird dann in einem Type XMLFile gespeichert und dort kann jetzt nach Befehlen gesucht werden (XMLFile.GetNode(Path)). Path gibt hierbei an, um welchen Knoten es sich handelt. Für dein Beispiel wäre es, wenn du bspw. den Wert für die anzahl der Cylinders herausfinden möchtest, der hier : "vehicle\engine\cylinders". Hast du z.B. mehrere Nodes mit dem Selben Namen in der Selben ebene, also bspw. in der Ebene "Vehicle" mehrere Nodes die z.B. "Typ" heißen oder so, so kannst du ganz einfach angeben welche du meinst, in dem du hinter den Namen noch ein [ID] schreibst, also z.B. so : "vehicle\typ[1]\name" oder "vehicle\typ[2]\name" etc. Wenn du eine unbestimmte anzahl hast, kannst du auch zählen lassen, wie viele Nodes sich in der Ebene befinden, sie werden alle von GetNodes(path) in einem String-Array zurückgegeben als direkten Pfad, kann also in einer For-Eachin schleife durchlaufen werden. Lg |
||
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt! |
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
BlitzMax: [AUSKLAPPEN] While(x < NumberOfParams) Das funktioniert nicht, wenn das Array, das du ausließt, eine andere Größe hat, als du anzunehmen beliebst.
Besser: BlitzMax: [AUSKLAPPEN] For Local i:Int=0 Until ParamWithOutZoll.Length Wenn du die Datei XML nennst, solltest du dich einigermaßen an den Standard halten - Dinge wie BlitzMax: [AUSKLAPPEN] If(Left(Line, 7) = "<motion")funktionieren, solange niemand Kommentare oder Verschachtelungen benutzt. Wenn die Datei für Benutzer editierbar sein soll, wäre es gut, wenn du klar irgendwo angibst, was man nicht tun darf. Am einfachsten wäre es dann, ein eigenes Textformat zu benutzen, was du sogar leichter auswerten könntest als XML. |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Macintosh |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Zum parsen von String oder XML nutze ich immer eine Selbstgeschriene "Scanner" klasse. sowie NSScanner aus dem Cocoa framework.
So geht das meiner meinung nach am einfachsten und schnellsten. |
||
![]() |
Propellator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ein alternativer Weg wäre Einstellungen in Lua-Scriptfiles zu speichern. BlitzMax hat einen Lua-Parser/Interpreter, und als voll ausgefleischte Scriptsprache gäbe es dem Benutzer auch die Möglichkeit gewisse Kontrollstrukturen in den Settings zu benutzen.
Ich habe schon andere Leute Lua als Werkzeug für Einstellungen benutzen sehen, jedoch selbst wenig Erfahrung damit. MfG |
||
Propellator - Alles andere ist irrelephant.
Elefanten sind die Könige der Antarktis. |
CO2ehemals "SirMO" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Gut, habe nun ein wenig rumexperimentiert, folgende (zufriedenstellende) Version ist herausgekommen:
BlitzMax: [AUSKLAPPEN] Function CopyStringToChar:String(Text:String, Char:String) Folgende Funktion sind enthalten: Code: [AUSKLAPPEN] -> CopyStringToChar(Text:String, Char:String)
Parameter: -Text: Die Zeile in der bis zu einem Zeichen kopiert werden soll -Char: Das Zeichen bis zu dem kopiert werden soll Beschreibung: Kopiert einen String bis zu einem Zeichen. Rückgabe: kopierter String -> DeleteStringToChar(Text:string, Char:string) Parameter: -Text: Die Zeile in der bis zu einem Zeichen alles gelöscht werden soll -Char: Das Zeichen bis zu dem gelöscht werden soll Beschreibung: Löscht einen String bis zu einem Zeichen Rückgabe: Übrig gebliebener String -> CopyStringFromChar(Text:string, Char:string) Parameter: -Text: Die Zeile in der von einem Zeichen kopiert werden soll -Char: Zeichen von dem kopiert werden soll Beschreibung: Kopiert einen String von einem Zeichen aus Rückgabe: kopierter String -> GetParamBetweenTag(Line:String) Parameter: -Line: Die Zeile in der die Tags stehen (Wichtig: Zeile muss wie folgt aufgebaut sein: <TAGNAME>AUSZULESENDER-WERT</TAGNAME>, da sonst nichts zurückgegeben wird) Beschreibung: Liefert den Wert zwischen einem öffnenden und einem schließenden Tag aus. Rückgabe: Ausgelesener Wert -> GetParamInTag(Line:string, ParamsCount:String, ParamsSaver:string[]) Parameter: -Line: Die Zeile in der das Tag steht -ParamsCount: Anzahl der auszulesenden Parameter (kleinster wert: 1) -ParamsSaver: Array in dem die ausgelesenen Parameter gespeichert werden. Beschreibung: Liefert die Werte in einem Tag aus (Beispiel: <motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/> Rückgabe: Nichts (Ausgelesene Parameter werden in dem Array ParamsSaver gespeichert) ich weiß, nichts besonderes, allerdings reicht es für meine zwecke. Mein xml-Parser sieht nun insgesamt wie folgt aus: BlitzMax: [AUSKLAPPEN] 'FOR VEHICLES Das XML-Format auf dem aufgebaut wurde sieht so aus: Code: [AUSKLAPPEN] <?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!-- Author: Marius Otto, CO2 Software File: vehicles.xml Date: 03.01.2012 --> <vehicles count="1"> <!-- ##################################################################################### FORM: <vehicle> <id>$CLASS_ID$</id> <name>NAME</name> <model file="[FILENAME]"/> <motion accelerate="[VALUE]" deccelerate="[VALUE]" maxspeed="[VALUE]"/> <mutliplayer active="[BOOL]"> <seat>VALUE</seat> </multiplayer> <engine> <fuel type="[TYPE*]" usage="[VALUE]" capacity="[VALUE]"/> <cylinder>VALUE</cylinder> <horsepower>VALUE</horsepower> <gearsystem type="[TYPE**]"> <gears>VALUE</gears> </gearsystem> </engine> <coords> <turnpoint x="[POSITION]" y="[POSITION]"/> <exhaustsystem count="[VALUE***]"> <exhaustpoint x="[POSITION]" y="[position]"/> </exhaustsystem> </coords> <ddm active="[BOOL]" type="[TYPE****]"> </vehicle> ##################################################################################### - *) FUEL TYPES: 1 = gas; 2 = diesel; 3 = kerosene - **) GEARSYSTEM TYPES: 1 = automatic; 2 = semi-automatic; 3 = only manual - ***) This value describes how many exhaustpoints are needed, e.g.: If this is "2" you need to define 2 exhaustpoints - ****) DDM-TYPES: "std" = standart; "adv" = advanced --> <vehicle> <id>$VEH_AMBULANCE$</id> <name>Krankenwagen</name> <model file="mod\ambulance.2dm"/> <motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/> <multiplayer active="true"> <seat>6</seat> </multiplayer> <engine> <fuel type="2" usage="0.002" capacity="85"/> <cylinder>6</cylinder> <horsepower>125</horsepower> <gearsystem type="1"> <gears>4</gears> </gearsystem> </engine> <coords> <turnpoint x="42" y="160"/> <exhaustsystem count="1"> <exhaustpoint x="14" y="199"/> </exhaustsystem> </coords> <ddm active="true" type="std"/> </vehicle> </vehicles> EDIT: Zu den Tipps mit den Modulen: Die sind mir alle zu groß, ich brauche einen "leichten" xml-parser (im übrigen muss der auch nicht viel können). ![]() mfG, CO2 |
||
mfG, CO²
Sprachen: BlitzMax, C, C++, C#, Java Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group