Einzelnen Beitrag anzeigen

Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.057 Beiträge
 
Delphi XE2 Professional
 
#10

Re: Substring an bestimmter Position im String?

  Alt 4. Aug 2006, 20:23
Zitat von 3_of_8:
Meine Idee wäre jetzt sowas gewesen:
Ich rufe AnsiLowerCase auf, denn substr steht in eax.
Dann pushe ich eax auf den Stack und lade edx (wo s steht) nach eax, rufe wieder AnsiLowerCase auf und lade eax nach edx.
Dann poppe ich eax wieder runter.
Gibt nur ne AV. Warum? Was mache ich falsch?
@Manuel,
Wenn Du AnsiLowerCase aufrufst, dann werden dort EDX und auch ECX verändert, d.h. sowohl @s und p sind nicht mehr verfügbar.
Du könntest das lösen, indem Du vor Aufruf von AnsiLowerCase die Register rettest, z.B.

push ecx
push edx
call AnsiLowerCase
xchg [esp],eax // @LowerCase(substr) auf Stack, EAX=@s
call AnsiLowerCase
mov edx, eax // @LowerCase(s)
pop eax // @LowerCase(substr)
pop ecx // p

Aber das wäre eher kontraproduktiv weil damit die Performance im Eimer ist.

Ich hab das mal ungeschrieben in 3 Funktionen

1) StrAtPos = binärer Vergleich
2) TextAtPos = arbeitet case insensitiv für A..Z / a..z
3) AnsiTextPos = arbeitet komplett case insensitiv

Um die Längenprüfung nicht in allen Funktionen vornehmen zu müssen, habe diese in eine separate Prozedur _CheckLengths ausgelagert.
Das Retten der Register EDI und ESI wird in _CheckLengths vorgenommen, d.h. EDI und ESI müssen in ..AtPos nicht auf den Stack gelegt, jedoch am Ende vom Stack genommen werden.
Wenn bereits die Längenprüfung ein False ergibt, dann wird nicht in die ..AtPos Funtionen zurückgekehrt sondern dorthin von wo ..AtPos aufgerufen wurde (und es wird natürlich False zurückgegeben).
Damit entfällt auch in den ..AtPos Funktionen die Prüfung des Resultates von _CheckLengths.
Ist ein bischen trickie, funktioniert aber.
Wenn mir nicht grobe Fehler unterlaufen sind, sollten die Funktionen das tun was sie tun sollen.

Delphi-Quellcode:
// Subroutine für die Funktionen StrAtPos, TextAtPos, AnsiTextAtPos
// --> EAX=@substr, EDX=@s, ECX=p
// Prüft ob die strings s und subst nicht leer sind und ob s lang genug ist,
// um ab s[p] substr enthalten zu können. Wenn p=0 ist, wird p=1 angenommen.
// Mögliche Resultate:
// 1) Einer der Stings ist leer oder s nicht lang genug:
// Rücksprung zu der Adresse, von der die aufrufende Funktion aufgerufen
// wurde mit dem Resultat False
// 2) Längenprüfung OK
// <-- EDI=@s[p], ESI=@Substr, ECX=Length(substr)
// EDI und ESI wurden auf den Stack gelegt und müssen von der aufrufenden
// Routine vom Stack genommen werden
PROCEDURE _CheckLengths;
asm
         xchg [esp],edi // EDI auf Stack, EDI=Returnadresse
         push esi // ESI auf Stack
         push edi // Returnadresse auf Stack
         test eax,eax
         je @Fail // substring leer
         test edx,edx
         je @Fail // s leer
         test ecx,ecx
         jne @1
         mov ecx,1
@1: mov esi,eax // @substr
         lea edi,[edx+ecx-1] // @s[p]
         mov eax,ecx // p
         mov ecx,[esi-4] // Lenght(substr)
         test ecx,ecx
         je @Fail // Lenght(substr)=0
         lea eax,[eax+ecx-1] // p+Length(substr)-1
         cmp eax,[edx-4]
         jbe @End
@Fail: xor eax,eax
         pop ecx // Resturnadresse der aufrufenden Funktion
         pop esi
         pop edi
@End:
end;


FUNCTION StrAtPos(const substr,s:string; p:integer):boolean;
asm
         call _CheckLengths
         mov edx,ecx
         shr ecx,2
         repe cmpsd // (Lenght(substr) div 4) mal 4 Bytes vergleichen
         jne @SetRes
@Bytes: mov ecx,edx
         and ecx,3
         repe cmpsb // (Lenght(substr) and 3) Bytes vergleichen
@SetRes: sete al
@End: pop esi
         pop edi
end;

FUNCTION TextAtPos(const substr,s:string; p:integer):boolean;
asm
         call _CheckLengths
@Loop: sub ecx,1
         jc @SetRes
         mov al,[esi+ecx] // Char aus substr
         mov dl,[edi+ecx] // Char aus s
         xor al,dl
         je @Loop // identisch
         cmp al,$20
         jne @Fail // nicht nur Bit 5 unterschiedlich
         and dl,$DF // Bit 5 in DL löschen (=UpperCase)
         cmp dl,'A'
         jb @Fail
         cmp dl,'Z'
         jbe @Loop
@Fail: clc
@SetRes: setc al
@End: pop esi
         pop edi
end;

FUNCTION AnsiTextAtPos(const substr,s:string; p:integer):boolean;
asm
         call _CheckLengths
@Loop: sub ecx,1
         jc @SetRes
         mov al,[esi+ecx] // Char aus substr
         mov dl,[edi+ecx] // Char aus s
         xor al,dl
         je @Loop // identisch
         cmp al,$20
         jne @Fail // nicht nur Bit 5 unterschiedlich
         and dl,$DF // Bit 5 in DL löschen (=UpperCase)
         cmp dl,'A'
         jb @Fail
         cmp dl,'Z'
         jbe @Loop
         cmp dl,$C0
         jb @Fail
         cmp dl,$D7
         je @Fail
         cmp dl,$df
         jne @Loop
@Fail: clc
@SetRes: setc al
@End: pop esi
         pop edi
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat