![]() |
ReverseString für ältere Delphi-Versionen
Wie aus diesem Thread
![]() hervorgeht, fehlt die Funktion ReverseString in älteren Delphi-Versionen. Daher lege ich als Ersatz meine Komposition noch einmal hier ab, damit man sie auch findet.
Delphi-Quellcode:
Gruß
//Wolfgang Mix - Delphi-PRAXiS
function ReverseString (MyString: string): string; var HelpString:string; i:integer; begin HelpString:=''; for i:=length(MyString) downto 1 do HelpString:=HelpString+MyString[i]; result:=HelpString; end; //Usage procedure TForm1.Button1Click(Sender: TObject); var String1,String2:String; begin String1:=Edit1.Text; String2:=ReverseString(String1); Edit2.Text:=String2; end; Wolfgang |
Re: ReverseString für ältere Delphi-Versionen
Ich hätte da noch eine schnellere Version im Kopf:
Delphi-Quellcode:
Optimierungen:
// (c) 2009 jfheins - member of Delphi-PRAXiS
function ReverseString (str: string): string; var i, len:integer; begin len := length(str); setlength(Result, len); for i := len downto 1 do Result[i] := str[len - i + 1]; end; 1. Wegfall des Hilfsstrings 2. Statt der Verkettung von String und Char jetzt mit setlength und Zugriff per Index Wobei ich mich (ein weiteres mal) frage, ob das nicht etwas sehr trivial ist - die Code-Library sollte ja gerade Qualität statt Quantität enthalten ;) |
Re: ReverseString für ältere Delphi-Versionen
Ich gebe Dir Recht, soon Ding coden wir in 5 Minuten,
aber Anfänger haben mit noch einfacheren Dingen Schwierigkeiten. Andererseits hat Embarcadingsbums noch trivialere Funktionen, wenn ich da an Tommorrow und Yesterday denke :mrgreen: Gruß Wolfgang |
Re: ReverseString für ältere Delphi-Versionen
Delphi-Quellcode:
Ihr wißt aber, daß die/unsere Ansi-Varianten nur mit Singelbyte-Zeichensätzen richtig arbeiten?
Function ReverseString(Const Text: String): String;
Var L: Integer; S, D: PChar; Begin L := Length(Text) - 1; SetLength(Result, L + 1); S := PChar(Text); D := PChar(Result) + L; For L := L downto 0 do Begin D^ := S^; Inc(S); Dec(D); End; End; Und weil ich grad mal 'nen Sekündchen lang Lange Weile hatte: :oops:
Delphi-Quellcode:
Und weil ich einfach zu doof bin, um die Funktionen der System-Unit aufzurufen
Function ReverseString(Const Text: AnsiString): AnsiString; Overload;
ASM PUSH EDI PUSH ESI PUSH EDX PUSH EAX XCHG EAX, EDX TEST EDX, EDX JZ @@ZeroSet SUB EDX, 4 MOV EDX, [EDX] @@ZeroSet: CALL _LStrSetLength POP ESI POP EDI MOV EDI, [EDI] SUB EDI, 4 MOV ECX, ESI TEST ECX, ECX JZ @@Exit SUB ECX, 4 MOV ECX, [ECX] //XOR EAX, EAX //@@Loop: //MOV DL, [ESI + EAX] //MOV [EDI + ECX], DL //INC EAX //LOOP @@Loop //@@Exit: PUSH ECX MOV EAX, ECX AND EAX, $3 ADD EDI, EAX SHR ECX, 2 // TEST ECX, ECX // wenn SHR das Zero-Flag nicht setzt, dann dieses einfügen JZ @@None4 XOR EAX, EAX @@Loop4: MOV EDX, [ESI + EAX * 4] BSWAP EDX MOV [EDI + ECX * 4], EDX INC EAX LOOP @@Loop4 @@None4: POP EAX MOV ECX, EAX AND ECX, $3 JZ @@Exit AND EAX, $FFFFFFFC @@Loop: MOV DL, [ESI + EAX] MOV [EDI + ECX + 1], DL INC EAX LOOP @@Loop @@Exit: POP ESI POP EDI End; {$IFDEF UNICODE} Function ReverseString(Const Text: UnicodeString): UnicodeString; Overload; ASM PUSH EDX PUSH EAX XCHG EAX, EDX TEST EDX, EDX JZ @@ZeroSet SUB EDX, 4 MOV EDX, [EDX] @@ZeroSet: CALL _UStrSetLength POP ESI POP EDI MOV EDI, [EDI] SUB EDI, 2 MOV ECX, ESI TEST ECX, ECX JZ @@Exit SUB ECX, 4 MOV ECX, [ECX] XOR EAX, EAX @@Loop: MOV DX, [ESI + EAX * 2] MOV [EDI + ECX * 2], DX INC EAX LOOP @@Loop @@Exit: End; {$ENDIF} Function ReverseString(Const Text: WideString): WideString; Overload; ASM PUSH EDX PUSH EAX XCHG EAX, EDX TEST EDX, EDX JZ @@ZeroSet SUB EDX, 4 MOV EDX, [EDX] SHR EDX, 1 @@ZeroSet: CALL _WStrSetLength POP ESI POP EDI MOV EDI, [EDI] SUB EDI, 2 MOV ECX, ESI TEST ECX, ECX JZ @@Exit SUB ECX, 4 MOV ECX, [ECX] SHR ECX, 1 XOR EAX, EAX @@Loop: MOV DX, [ESI + EAX * 2] MOV [EDI + ECX * 2], DX INC EAX LOOP @@Loop @@Exit: End; (ich hasse es, daß die Namen der System.pas nicht mit der System.dcu und der CPU-Anzeige übereinstimmen)
Delphi-Quellcode:
Procedure _LStrSetLength(Var Text: AnsiString; Len: Integer);
Begin SetLength(Text, Len); End; {$IFDEF UNICODE} Procedure _WStrSetLength(Var Text: WideString; Len: Integer); Begin SetLength(Text, Len); End; {$ENDIF} Procedure _UStrSetLength(Var Text: UnicodeString; Len: Integer); Begin SetLength(Text, Len); End; |
Re: ReverseString für ältere Delphi-Versionen
@himitsu:
Zitat:
Ausserdem ist es viel spannender, die Probleme selber zu lösen. :) Gruß Wolfgang |
Re: ReverseString für ältere Delphi-Versionen
Inzwischen denke ich, dass das Thema trotz aller Simplizität doch Wert ist,
in der CodeLib untergebracht zu werden. |
Re: ReverseString für ältere Delphi-Versionen
Hi,
ich verstehe euren Programmiertechnischen Aufwand nicht. :duck:
Delphi-Quellcode:
function ReverseAnsiString(const s: Ansistring): Ansistring;
var i : integer; begin for i := length(s) downto 1 do Result := Result + s[i]; end; |
Re: ReverseString für ältere Delphi-Versionen
Vielleicht, weil dein Code nicht wirklich gut arbeitet?
Und weil er über 20 Mal langamer ist, als mein Pascal-Code? :angel2: Also inkl. dem Result:=''; ansonsten bremst es je Aufruf natürlich noch extremer ab, da ja der Resultstring immer größer wird. (der Code von jfheins ist dagegen 3 Mal schneller, bei einem 10 Zeichen langem String, wärend dein Code eine expotentiell steigende Zeit zur Stringlänge hat und unsere Codes arbeiten linear) Dein String ist nicht initialisiert.
Delphi-Quellcode:
probier es mal aus ... du wirst ganz schön erstaunt sein
function ReverseAnsiString(const s: Ansistring): Ansistring;
var i : integer; begin Result := ''; for i := Length(s) downto 1 do Result := Result + s[i]; end;
Delphi-Quellcode:
var S, S2: AnsiString;
i: Integer; S := '123'; for i := 0 to 9 do begin S2 := ReverseString(S); ShowMessage(S2); end; |
Re: ReverseString für ältere Delphi-Versionen
Zitat:
sicherlich, guter Style ist es nicht. Mit der Geschwindigkeit kann es schon so sein, da Setlengt den Stringzähler " s[0] := x " (klappt ja bei Delphi nur noch per Umweg [SetLength]) den ben. Platz gleich reserviert ohne ihn jedes mal erneut um eins zu erhöhen. Vill. bin ich auch nur zu müde um richtig nachdenken zu können. ;) |
Re: ReverseString für ältere Delphi-Versionen
Nein, beim Result ist es was Anderes, der wird nicht automatisch initialisiert, so wie es bei normalen Variablen der Fall ist.
Wie gesagt, probier es einfach mal aus. ShowMessage zeigt nacheinander dieses an: 1. Aufruf: Result/S=321 2. Aufruf: Result/S=321321 3. Aufruf: Result/S=321321321 4. Aufruf: Result/S=321321321321 5. Aufruf: Result/S=321321321321321 6. Aufruf: Result/S=321321321321321321 7. Aufruf: Result/S=321321321321321321321 8. Aufruf: Result/S=321321321321321321321321 9. Aufruf: Result/S=321321321321321321321321321 10. Aufruf: Result/S=321321321321321321321321321321 Dieser Code:
Delphi-Quellcode:
enspricht intern eigentlich diesem:
function ReverseString(const s: Ansistring): Ansistring;
var i : integer; begin for i := Length(s) downto 1 do Result := Result + s[i]; end; var S, S2: AnsiString; i: Integer; S := '123'; for i := 0 to 9 do begin S2 := ReverseString(S); ShowMessage(S2); end;
Delphi-Quellcode:
Und nun erkennt man bestimmt auch, warum es dort nicht funktioneren kann.
procedure ReverseString(const s: Ansistring; var Result: Ansistring);
var i : integer; begin for i := Length(s) downto 1 do Result := Result + s[i]; end; var S, S2: AnsiString; i: Integer; S := '123'; for i := 0 to 9 do begin ReverseString(S, S2); ShowMessage(S2); end; |
Re: ReverseString für ältere Delphi-Versionen
@Himitsu:
So ähnlich wollte ich auch antworten. Ich hab mal getestet wie schnell/langsam die Routinen sind und habe auch noch eine eigene Routine dazu gestellt.
Delphi-Quellcode:
Die Angaben sind CPU-Ticks.
PROCEDURE ReverseStr(var s:string);
var p1,p2:PChar; c:Char; begin if s='' then exit; p1:=@s[1]; p2:=p1+Length(s)-1; while p1<p2 do begin c:=p1^; p1^:=p2^; p2^:=c; inc(p1); dec(p2); end; end; Gemessen wurde auf Basis eines Strings mit 10 Zeichen.
Code:
zu letzterer sei angemerkt, dass diese Routine eine Prozedur ist, der Vergleich mit den Funktionen ist also nicht ganz fair.
#1 von Wolfgang Mix : 12650
#2 von jfheins : 450 #4 von himitsu : 280 #7 von turboPASCAL : 11660 #11 von amateurprofi : 45 |
Re: ReverseString für ältere Delphi-Versionen
Und nochmal @himitsu:
Die Systemroutinen kannst du mit z.B. CALL System.@LStrSetLength aufrufen. Zu deiner Assembler Routine: Hast du die mal getestet ? Bei Längen im Bereich 1 bis 3 gibts Probleme. Warum?: ECX enthält Length(Text). Wenn ECX<4 ist dann wird ECX durch SHR ECX,2 auf 0 gestellt. Das Loop senkt dann ECX um 1 und springt zu @@Loop4, bis ECX=0 ist. Die Schleife wird also 2^32 mal durchlaufen, bzw. bis es 'ne Exception gibt.
Delphi-Quellcode:
Bei Längen > 3 funktioniert die Routine zwar, aber dafür funktioniert danach irgend etwas anderes nicht mehr.
SHR ECX, 2
XOR EAX, EAX @@Loop4: MOV EDX, [ESI + EAX * 4] BSWAP EDX MOV [EDI + ECX * 4], EDX INC EAX LOOP @@Loop4 Warum ?: Weil du EDI und ESI veränderst. Ich hab die Idee mit dem bswap aufgegriffen.
Delphi-Quellcode:
FUNCTION ReverseStr_A(s:string):string;
asm test eax,eax jne @Start mov eax,edx jmp system.@LStrClr @Start: push edi mov edi,edx push eax mov edx,[eax-4] mov eax,edi call System.@LStrSetLength pop edx // @s[1] mov ecx,[edx-4] // Length(s) mov edi,[edi] // @result[1] jmp @NextDW @DWLoop: mov eax,[edx+ecx] bswap eax stosd @NextDW: sub ecx,4 jnc @DWLoop add ecx,3 js @End @BLoop: mov al,[edx+ecx] stosb sub ecx,1 jnc @BLoop @End: pop edi end; |
Re: ReverseString für ältere Delphi-Versionen
Ups, das mit EDI und ESI hatte ich ganz vergessen :oops: (dachte die waren so wie EAX, EDX und ECX)
joar, und das mit dem <4 stimmt :? hab es oben mal geändert für "sub ecx,1" würde wohl auch "dec ecx" gehn und "loop @BLoop" entspricht einem "dec ecx; jnz @BLoop", aber ich weiß hier nicht, welches optimaler arbeitet "call @LStrSetLength" hatte ich aber probiert und ich wäre nicht drauf gekommen, daß man den System-Namespace unbedingt verwenden muß :shock: Joat und das stord/storb macht sich auch besser, wenn man eh schon esi/edi verwendet :thumb: |
Re: ReverseString für ältere Delphi-Versionen
Intel empfiehlt statt INC xxx / DEC xxx besser ADD xxx,1 / SUB xxx,1 zu verwenden (weil schneller).
Und LOOP ist deutlich langsamer als SUB ECX,1; JNZ . Deshalb ist die von mir gezeigte Version auch erheblich schneller.... |
Re: ReverseString für ältere Delphi-Versionen
:shock:
Also bei INC/DEC hätte ich es genau andersrum gedacht, da dese doch eigentlikch weniger machen, im Gegensatz zum ADD/SUB :gruebel: (nja, ich hab 'nen AMD und keinen Intel :mrgreen: ) und beim LOOP hätte ich mindestens fast gleich schnell erwartet. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:28 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-2025 by Thomas Breitkreuz