Autor |
Beitrag |
delphi10
      
Beiträge: 447
Erhaltene Danke: 2
W2K, XP, Vista64, Win7 64
RAD-Studio 2010
|
Verfasst: Sa 16.10.10 01:29
Hallo
Warum erzeugt dieses For-Konstrukt
Delphi-Quelltext 1: 2: 3:
| For x := 1 to length(ErrorText) do if ErrorText[x] = '&' then delete(ErrorText,Pos('&',ErrorText),1); |
keine Fehlermeldung wenn im Text ein oder mehrere & vorkommen? Durch die Änderung der to-Varible würde ich einen Fehler erwarten, läuft aber einwandfrei.
Gruss Delphi10
_________________ Salus populi suprema lex esto
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Sa 16.10.10 01:35
Für diesen Beitrag haben gedankt: delphi10
|
|
elundril
      
Beiträge: 3747
Erhaltene Danke: 123
Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
|
Verfasst: Sa 16.10.10 01:56
In dem Fall würde ich aber ne FOR-IN-Schleife verwenden, wenn du schon das RAD-Studio 2010 hast. Nur so zur Sicherheit. Weil da wird dann jedes Element genau einmal ausgewählt (Falls es überhaupt mit Strings geht, aber eigentlich sollte es).
_________________ This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
Für diesen Beitrag haben gedankt: delphi10
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Sa 16.10.10 02:02
elundril hat folgendes geschrieben : | In dem Fall würde ich aber ne FOR-IN-Schleife verwenden, wenn du schon das RAD-Studio 2010 hast. Nur so zur Sicherheit. Weil da wird dann jedes Element genau einmal ausgewählt (Falls es überhaupt mit Strings geht, aber eigentlich sollte es). |
Ich würde mich beim Programmieren nicht auf irgendwelche Schalterstellungen in der IDE verlassen. Richtig wäre, die Schleife runter zählen zu lassen, und das auch entsprechend zu coden.
Für diesen Beitrag haben gedankt: Hidden
|
|
delphi10 
      
Beiträge: 447
Erhaltene Danke: 2
W2K, XP, Vista64, Win7 64
RAD-Studio 2010
|
Verfasst: Sa 16.10.10 02:03
elundril hat folgendes geschrieben : | In dem Fall würde ich aber ne FOR-IN-Schleife verwenden, wenn du schon das RAD-Studio 2010 hast. Nur so zur Sicherheit. Weil da wird dann jedes Element genau einmal ausgewählt (Falls es überhaupt mit Strings geht, aber eigentlich sollte es). |
Das stammt noch aus einem alten Projekt mit Studio 2006 das ich gerade aufmöbele. Trotzdem Danke.
Der Hinweis von @Gerd Kayser hat meinem organischen Speicher wieder reorganisiert. Man(n) wird älter.
_________________ Salus populi suprema lex esto
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 07:18
Zu deiner Ausgangsfrage: Wenn du die Bereichsüberprüfung nicht angeschaltet hast, merkt dein Programm ganz einfach nicht, dass es ggf. bereits hinter dem Ende des Strings liest.
Solange hinter dem Speicherbereich des Strings also keine nicht zugreifbaren Speicherbereiche liegen, kommt auch keine Zugriffsverletzung. Sollte da zufällig ein Zeichen gefunden werden, weil da diese Bytewerte liegen, passiert auch kein Schreibzugriff, da Delete nichts tut, da der Zugriff hinter dem Ende des Strings liegt.
Wenn du einen String versucht hättest, bei dem zwei der gesuchten Zeichen hintereinander liegen, hätte es nicht funktioniert, da das zweite Zeichen nach dem Delete aufgerückt ist und nicht mehr geprüft wird.
elundril hat folgendes geschrieben : | In dem Fall würde ich aber ne FOR-IN-Schleife verwenden, wenn du schon das RAD-Studio 2010 hast. Nur so zur Sicherheit. Weil da wird dann jedes Element genau einmal ausgewählt (Falls es überhaupt mit Strings geht, aber eigentlich sollte es). |
Ja, es geht mit Strings. In diesem Fall aber nicht, denn es soll ja gerade der String verändert werden. Und das geht nicht, wenn for...in benutzt wird. Denn das funktioniert wie jede andere for-Schleife: Die Randbedingungen werden vorher ausgelesen.
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 16.10.10 08:12
Wahrscheinlich wäre hier ein While-Konstrukt besser. Möglicherweise ist der jedoch nicht so schnell, da jedesmal ein Pos(sub,s) abgefragt wird, aber er sollte alle Zeiche(folgen) erfassen:
Delphi-Quelltext 1: 2:
| while Pos('&',Errortext)>0 do Delete(ErrorText,Pos('&',ErrorText),1); |
Dies gilt natürlich nur, wenn nicht ausdrücklich eine FO-Schleife gefordert ist.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 08:15
Das ist hier aber deutlich ungünstiger (noch verstärkt dadurch, dass du das Ergebnis von Pos nicht einmal zwischenspeicherst).
Der bereits genannte Weg mit der umgedrehten for-Schleife ist schon der richtige. Das funktioniert auch, ist aber deutlich schneller.
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 16.10.10 08:19
Sicher, für das Löschen einzelner Zeichen ist mein Konstrukt sicher langsamer als eine For-Schleife. Doch was ist mit dem Löschen einer Zeichenfolge? Z.B. statt '&' '###' oder ...? Dann wird ein For-Konstrukt deutlich komplizierter, oder? Außerdem, wenn das Zeichen in einem String als Platzhalter für andere Texte steht? Dann ist das in einer umgekehrten FOR-Schleife ebenfalls nicht so einfach machbar.
Flexibilität ist leider oft mit Geschwindigkeitsverlust verbunden.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 08:30
Erstens gibt es dann noch StringReplace, das wahrscheinlich immer noch besser optimiert ist, zweitens ist das nicht so schwer. Mal so runtergeschrieben, sollte funktionieren: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| function DeleteFromString(const AFrom, ADelString: string): string; var i, CurPos: Integer; begin Result := AFrom; if (Length(AFrom) > 0) and (Length(ADelString) > 0) then begin CurPos := Length(ADelString); for i := Length(Result) downto 1 do if ADelString[CurPos] = AFrom[i] then if CurPos = 1 then begin Delete(Result, i, Length(ADelString)); CurPos := Length(ADelString); end else Dec(CurPos) else CurPos := Length(ADelString); end; end; | Mit Boyer-Moore könnte man noch ein bisschen mehr Geschwindigkeit herausholen. 
Für diesen Beitrag haben gedankt: delphi10
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Sa 16.10.10 11:24
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 11:27
Die Optimierung passiert nur im Hintergrund. Diese hat aber keinen Effekt auf die tatsächlich angesprochenen Indizes des Strings...
Dass die Schleife in Wirklichkeit rückwärts läuft, hat also keinen Effekt. Wäre ja auch schlimm sonst.
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Sa 16.10.10 12:34
jaenicke hat folgendes geschrieben : | Die Optimierung passiert nur im Hintergrund. Diese hat aber keinen Effekt auf die tatsächlich angesprochenen Indizes des Strings...
Dass die Schleife in Wirklichkeit rückwärts läuft, hat also keinen Effekt. Wäre ja auch schlimm sonst. |
Ich habe gerade versucht, dieses Verhalten nachzustellen. Leider ohne Erfolg. Entweder war ich da auf dem Holzweg oder meine Erinnerung trügt mich. Ich meine vor etwa einem Jahr eine Schleife programmiert zu haben, die sich anders als erwartet verhielt, und demzufolge Murks produzierte.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| procedure TMainform.Button1Click(Sender: TObject); var EinString : string; Schleife : integer; begin EinString := 'Hallo Welt'; for Schleife := 1 to Length(EinString) do if EinString[Schleife] = 'l' then Delete(EinString,Pos('l',EinString),1); ShowMessage(EinString); end;
procedure TMainform.Button2Click(Sender: TObject); var EinString : string; Schleife : integer; begin EinString := 'Hallo Welt'; for Schleife := Length(EinString) downto 1 do if EinString[Schleife] = 'l' then Delete(EinString,Pos('l',EinString),1); ShowMessage(EinString); end; |
Wie dem auch sei: Beide Prozeduren liefern jedenfalls unterschiedliche Ergebnisse.
Prozedur 1: Hao Welt
Prozedur 2: Hao Wet
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 12:50
Naja, ist ja logisch, du prüfst an der Stelle der Schleifenvariablen und löschst an der ersten Position des Zeichens... Dass es dann einen Unterschied zwischen den Laufrichtungen gibt, ist klar. 
|
|
delphi10 
      
Beiträge: 447
Erhaltene Danke: 2
W2K, XP, Vista64, Win7 64
RAD-Studio 2010
|
Verfasst: Sa 16.10.10 12:51
jaenicke hat folgendes geschrieben : | Erstens gibt es dann noch StringReplace, das wahrscheinlich immer noch besser optimiert ist, zweitens ist das nicht so schwer. Mal so runtergeschrieben, sollte funktionieren: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| function DeleteFromString(const AFrom, ADelString: string): string; var i, CurPos: Integer; begin Result := AFrom; if (Length(AFrom) > 0) and (Length(ADelString) > 0) then begin CurPos := Length(ADelString); for i := Length(Result) downto 1 do if ADelString[CurPos] = AFrom[i] then if CurPos = 1 then begin Delete(Result, i, Length(ADelString)); CurPos := Length(ADelString); end else Dec(CurPos) else CurPos := Length(ADelString); end; end; | Mit Boyer-Moore könnte man noch ein bisschen mehr Geschwindigkeit herausholen.  |
Ich hab das mal eben implantiert. Läuft einwandfrei, wobei mir eine Optimierung nicht so wichtig ist. Hier werden Systemmeldungen für einen Mailbody zusammengestellt - da ist dann sowieso alles zu spät. Dummerweise verträgt Outlook im automatisch generierten Bodytext keine '&', daher der Aufwand.
Gruß Delphi10
edit: Die For-Schleife erwischt in der Tat nur einzelne '&', wenn mehrere hintereinander stehen versagt die Methode.
_________________ Salus populi suprema lex esto
|
|
Tilman
      
Beiträge: 1405
Erhaltene Danke: 51
Win 7, Android
Turbo Delphi, Eclipse
|
Verfasst: Sa 16.10.10 16:51
1. Der ganz Obenstehende Code funktioniert bei mir nicht, voraussetzend dass er alle & in einem text löschen soll: aus "salbader&&&blubl&&ub&" wird "salbaderblubl&ub&"
2. Ich mache das immer so, wenn ich z.B. aus Listen lösche, und funktioniert einwandfrei:
Delphi-Quelltext 1: 2: 3:
| For x := length(ErrorText) downto 1 do if ErrorText[x] = '&' then delete(ErrorText,Pos('&',ErrorText),1); |
Hier wird zwar die From-Klausel geändert, aber das aktuelle Element ist stets gültig, und ich hatte noch nie Probleme damit.
_________________ Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 17:23
|
|
Tilman
      
Beiträge: 1405
Erhaltene Danke: 51
Win 7, Android
Turbo Delphi, Eclipse
|
Verfasst: Sa 16.10.10 17:28
Jo jaenicke da hast du recht, hatte mir den Code nicht genau genug angesehen, muss natürlich Delphi-Quelltext 1: 2: 3:
| For x := length(ErrorText) downto 1 do if ErrorText[x] = '&' then delete(ErrorText,x,1); | lauten
_________________ Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Sa 16.10.10 17:49
Was hindert euch jetzt eigentlich daran, die Perfomance zu ignorieren und
Delphi-Quelltext 1:
| StringReplace(ErrorText, '&','',[rfReplaceAll]) |
zu verwenden?
Duct Tape Programming: funktionierender (und selbstdokumentierender) Code zuerst, optimieren kann man immer noch, wenn sich Probleme zeigen. Und das dürfte bei einer Funktion die Mails verschickt wohl nicht passieren...
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: delphi10
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.10.10 18:29
Ja, die Funktion hatte ich ja auch schon erwähnt. Die eigene Funktion war vor allem ne Demo, dass es durchaus einfach ist. 
|
|
|