![]() |
String nach bestimmten muster auflösen
Hallo zusammen, ich habe folgendes Problem.
Ich will ein Programm schreiben, mit dem ich mittels eigenen Textbefehlen aus einem editfeld in einer Imagekomponente zeichnen kann. Also z.B. V90R45V90 soll 90px "nach vorne" zeichnen, dann wird um 45 grad nach rechts gedreht und wieder 90px in die neue richtung gezeichnet. Außerdem gibt es noch wiederholungsbefehle, die zb so aussehen könnten: W4(v90r45). In dem fall soll das in der klammer 4 mal wiederholt werden. Mein problem ist jetzt das umschreiben dieser wiederholungsstrings. Mein ansatz war, den inhalt der klammern in einen neuen string zu speichern und diesen dann eben entsprechend oft zu wiederholen. Durch eine while schleife ermittle ich, wo sich die erste und zweite klammer des jeweiligen W befindet und speichere dann den Inhalt in einem neuen string. Meine frage also jetzt, wie mache ich es, dass der string so lange aufgelöst wird, bis er keine wiederholungsbefehle mehr enthält, denn so ein string könnte ja auch so aussehen W2(w2(v90)), wenn man das auflöst, hätte man ja w2(v90)w2(v90), was wiederrum aufgelöst werden muss. Hier meine kleine Funktion, die den string auflösen soll: Meine Variablen repInt: gibt die Anzahl der wiederholungen an, die nach einem W steht wCount: Variable zum finden der zugehörigen klammer bracketPlace1/2: Position der ersten bzw. zweiten Klammer repStr: Der string, der wiederholt werden soll(dieser soll eigentlich dann voll aufgelöst und der rückgabestring sein) oldRepStr: der wiederholungsstring vom letzten schleifendurchlauf strToCopy: beinhaltet den befehl in einer klammer
Code:
PS: Ich weiß, dass manches da nach der while schleife nicht viel sinn gibt, aber das ist eben meine frage, wie ich nach der schleife weiter mache, sodass alles aufgelöst in einem string gespeichert wird.
function TForm1.interpretateString(str:string) : string;
var repInt, wCount, bracketPlace1, bracketPlace2, i, j: integer; repStr, oldRepStr, strToCopy: string; begin wCount:=0; bracketPlace2:=0; oldRepStr:=''; repStr:=''; for i:=1 to Length(str) do begin if str[i]='W' then begin repInt:=getCount(str, i); bracketPlace1:=i+Length(IntToStr(repInt))+2; j:=bracketPlace1; while wCount<>-1 do begin if str[j]=')' then begin wCount:=wCount-1; if wCount=-1 then begin //Delete(str, j, 1); bracketPlace2:=j+1; break; end; end else if str[j]='(' then begin wCount:=wCount+1; end; j:=j+1; end; strToCopy:=Copy(str, bracketPlace1, bracketPlace2-bracketPlace1-1); repStr:=repStr+repeatString(strToCopy, repInt); ShowMessage('repStr: '+repstr); oldRepStr:=repStr; ShowMessage('ors... '+ oldRepStr); result:=repStr+oldRepStr; end; end; end; Danke im vorraus |
AW: String nach bestimmten muster auflösen
Der einfachste Weg ist rekursiv.
Du zerlegst den Befehl und bei einer Klammer nimmst du den Zeil zwischen den Klammern und übergibst ihn ebenfalls an die Parserfunktion. Zwischen = Klammern zählen bei ( +1, bei ) -1 und wenn 0, dann ist das die zugehörige schließende Klammer. Bei W2 wird der Teilstring dann halt doppelt ausgewertet. Ansonsten lernst du was eine Iteration ist und baust die Rekursion entsprechend um. |
AW: String nach bestimmten muster auflösen
Nur mal am Rande;
Warum nimmst du nicht die gleichen Zeichenbefehle wie in ![]() Könnte sein das dies ![]() Bin zwar nicht sicher für alle Elemente, aber zumindest LineTo und MoveTo wird genauso wie in Inkscape geschrieben. Ich würde einfach mal einen Path in Inkscape schreiben so wie du ihn gerne hättest, und dann mal analysieren wie dies in Xml kodiert ist. Wahrscheinlich macht eine solche "Zeichensprache" mehr Sinn wenn sie möglichst kompatibel ist (Inkscape, FireMonkey TPathData). Rollo |
AW: String nach bestimmten muster auflösen
|
AW: String nach bestimmten muster auflösen
Zitat:
Langfristig würde ich darüber nachdenken, die Stringersetzung durch einen ![]() Mit einem ![]() |
AW: String nach bestimmten muster auflösen
So, hab es mal mit der Rekursion versucht, allerdings klappt das ganze noch nicht so. Es wird jetzt nur die erste Klammerebene aufgelöst, aber sobald eine wiederholung in einer klammer ist klappt das nicht mehr.
Code:
function TForm1.getRepStr(str:string; count:integer) : string;
var repInt, bracketPlace1, bracketPlace2, i, wCount : integer; repStr : string; begin wCount:=0; repInt:=getCount(str, count); bracketPlace1:=count+Length(IntToStr(repInt))+2; i:=bracketPlace1; while wCount<>-1 do begin if str[i]=')' then begin wCount:=wCount-1; if wCount=-1 then begin bracketPlace2:=i+1; break; end; end else if str[i]='(' then begin wCount:=wCount+1; end; i:=i+1; end; repStr:=Copy(str, bracketPlace1, bracketPlace2-bracketPlace1-1); repStr:=repeatString(repStr, repInt); ShowMessage('repStr: ' + repStr); if containsW(repStr)=true then repStr:=getRepStr(repStr, 1) else result:=repStr; end; |
AW: String nach bestimmten muster auflösen
Irgendwie so in der Art könnte es aussehen:
Delphi-Quellcode:
Geht auf jeden Fall noch eleganter, aber die Lösung hier sollte recht einfach zu verstehen sein. Die Funktion zerlegt den String in seine Einzelteile und ordnet die Befehle dann in einen TreeView ein.
function TForm2.ParseString(Root: TTreeNode; const S: String): Integer;
var I, J: Integer; T: TTreeNode; begin I := 1; while (I <= Length(S)) do begin if (S[I] in ['W', 'V', 'R']) then begin J := I + 1; while (J <= Length(S)) and (S[J] in ['0'..'9']) do begin Inc(J); end; T := TreeView1.Items.AddChild(Root, Copy(S, I, J - I)); if (S[I] = 'W') then begin Inc(I, J - I + ParseString(T, Copy(S, J + 1, Length(S)))); end else begin Inc(I, J - I); end; end else if (S[I] = ')') then begin Inc(I); Break; end else begin raise Exception.Create('Failed to parse string.'); end; end; Result := I; end; procedure TForm2.Button1Click(Sender: TObject); begin TreeView1.Items.Clear; TreeView1.Items.BeginUpdate; try ParseString(nil, AnsiUpperCase('V900W2(w2(v90))V90W5(V45)')); finally TreeView1.Items.EndUpdate; end; end; |
AW: String nach bestimmten muster auflösen
Hier mal Pseudocode.
Delphi-Quellcode:
Ganz grob skizziert.
procedure Parse;
begin While GetNextCommand(command) do Execute(command); end; Function GetNextCommand(var cmd : TCommand) : Boolean; var c : Char; Begin if AtEof Then Exit(False) c := TakeChar; if c=')' then Exit(False); if not (c in allowedCommands) then raise Exception.Create('Invalid command'); cmd := TCommand.Create; cmd.Command := c; cmd.Value := TakeNumber; if (cmd.Command = RepeatCmd) then if TakeChar<>'(' then Raise Exception.Create('Expected "("') result := True; End; Procedure Execute (aCmd : TCommand); Begin case aCmd.Command of RepeatCmd : Parse; ForwardCmd : GoForward (aCmd.Value); RightCmd : TurnRight(aCmd.Value); ... end end; Function AtEof : Boolean; Begin result := CurrentPtr>Length(InputString); End; Function TakeChar : Char; Begin result := InputString[CurrentPtr]; inc(CurrentPtr); End; Function TakeNumber : Integer; Var p : Integer; Begin p := CurrentPtr; While TakeChar in Digits and Not AtEof; if p=CurrentPtr then Raise Exception.Create('Not a number'); result := StrToInt(Copy(InputString,p,CurrentPtr-p)); end; Procedure Run (aString : String); Begin InputString := aString; CurrentPtr := 1; Parse; End; |
AW: String nach bestimmten muster auflösen
Danke erstmal für die vielen Antworten, das mit dem TreeView klappt zwar gut, doch wie mache ich es jetzt, dass ich eine Funktion habe, der man einen string mitgibt und dann den fertigen aufgelösten string wieder zurückgibt?
|
AW: String nach bestimmten muster auflösen
Zitat:
Auf die Schnelle aus dem Kopf:
Delphi-Quellcode:
procedure Execute(Node: TTreeNode);
var S: String; I, J: Integer; begin S := Node.Text; if (S[1] = 'W') then begin for I := 1 to {Anzahl an Iterationen} do begin for J := 0 to Node.Childs.Count - 1 do begin Execute(Node.Childs[J]); end; end; end else if (S[1] = 'V') then begin // .. end else if (S[1] = 'R') then begin // .. end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz