Registriert seit: 17. Nov 2005
Ort: Hamburg
1.076 Beiträge
Delphi XE2 Professional
|
AW: Alternative zu PosEx
27. Nov 2024, 11:44
Hier noch einmal die Asm-Funktionen StrPos und StrPosEx.
Die "StrPos" 64Bit ist korrigiert.
Wer Fehler findet soll die bitte nicht behalten sondern hier melden.
StrPos
Delphi-Quellcode:
{$IFDEF CPUX86}
{------------------------------------------------------------------------------}
{ StrPos 32bit }
{ Prüft, ob SearchFor in SearchIn innerhalb des Bereiches First..Last }
{ vorkommt und gibt die gefundene Position. bzw 0 für 'nicht gefunden' zurück. }
{ First<1 heißt ab Anfang von SearchIn suchen. }
{ Last<1 oder Last>Length(SearchIn) heißt bis Ende von SearchIn suchen. }
{------------------------------------------------------------------------------}
FUNCTION StrPos( const SearchFor,SearchIn: String; First,Last:NativeInt):Integer;
asm
// EAX=@SearchFor, EDX=@SearchIn, ECX=First, Stack=Last
test eax,eax
jz @ Nil // SearchFor leer
test edx,edx
jz @ Nil // SearchIn leer
dec ecx // First 0-Based
jge @FirstOk // First>=1
xor ecx,ecx
@FirstOK: push ebx
push edi
push esi
mov ebp,Last
mov ebx,[edx-4] // Length(SearchIn)
test ebp,ebp
jle @LastOK // Last<=0 heißt bis Ende suchen
cmp ebp,ebx
jge @LastOK // Last>Length(SearchIn), bis Ende suchen
mov ebx,ebp // Nur bis Last suchen
@LastOK: // EAX=@SearchFor, EDX=@SearchIn, ECX=First-1, EBX=Last
mov edi,[eax-4] // Length(SearchFor)
lea esi,[ecx+edi] // First+Length(SearchFor)-1
cmp esi,ebx
jg @Past // First>Last oder First+Length(SearchFor)>Last
lea eax,[eax+edi*2-2] // @SearchFor[Length(SearchFor)]
lea ebp,[edx+ebx*2] // @SearchIn[Last+1]
lea edx,[edx+esi*2-2] // @SearchIn[First+Length(SearchFor)-1]
lea edi,[edi*2-2] // 2*(Length(SearchFor)-1)
neg edi // -(2*(Length(SearchFor)-1))
add ecx,ecx // 2*(First-1)
sub ecx,edx // 2*(First-1)-@SearchIn[First+Length(SearchFor)-1]
push ecx // Für spätere Positionsberechnung
movzx ecx,word[eax] // letztes Zeichen von SearchFor
// --------------------------------------------------------------
// CX = Letztes Zeichen von SearchFor
// EDX = SearchIn[First+Length(SearchFor)
// EBP = @SearchIn[Last+1 Zeichen]
// EDI = -(2*(Length(SearchFor)-1))
// ESI = First+Length(SearchFor)-1
@Loop: cmp cx,[edx] // Letzes Zeichen von SearchFor an EDX?
jz @Test0 // Ja, SearchIn auf voriges Zeichen
@AfterTest0: cmp cx,[edx+2] // Letzes Zeichen von SearchFor an EDX+1 Zeichen
jz @TestT // J,
@AfterTestT: add edx,8 // SearchIn+4 Zeichen
cmp edx,ebp // SearchIn noch im zu durchsuchenden Bereich
jb @Continue // Ja
@EndLoop: add edx,-4 // SearchIn-2 Zeichen
cmp edx,ebp // SearchIn noch im zu durchsuchenden Bereich
jb @Loop // Ja
jmp @False // Nicht gefunden
@Continue: cmp cx,[edx-4] // Letzes Zeichen von SearchFor an EDX-2 Zeichen?
jz @Test2 // Ja, SearchIn -3 Zeichen
cmp cx,[edx-2] // Letzes Zeichen von SearchFor an EDX-1 Zeichen?
jnz @Loop // Nein, nächste Position prüfen
@Test1: add edx,2 // SearchIn + 1 Zeichen, durch folgende Adds - 2 Zeichen
@Test2: add edx,-4 // SearchIn - 2 Zeichen, durch folgendes Add - 3 Zeichen
@Test0: add edx,-2 // SearchIn - 1 Zeichen
@TestT: mov esi,edi
test esi,esi // Alle Zeichen von SearchFor gefunden?
jz @Found // Ja, gefunden
@ String: mov ebx,[eax+esi] // 2 Zeichen aus SearchFor
cmp ebx,[edx+esi+2] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn+4 Zeichen
cmp esi,-4 // Alle Zeichen gefunden?
jge @Found // Ja
mov ebx,[eax+esi+4] // Nächste 2 Zeichen aus SearchFor
cmp ebx,[edx+esi+6] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn+4 Zeichen
add esi,8 // Zeichenzahl + 4 Zeichen
jl @ String // Nächste 4 Zeichen prüfen
//---------------------------------------------------------------
@Found: lea eax,[edx+4] // Fundstelle
cmp eax,ebp // Im zu durchsuchenden Bereich?
ja @False // Nein, nicht gefunden.
add eax,[esp] // Endgültige Position in Bytes
shr eax,1 // Endgültige Position in Zeichen
jmp @ End // Stack bereinigen, Register wieder herstellen
//---------------------------------------------------------------
@False: xor eax,eax // Nicht gefunden
jmp @ End // Stack bereinigen, Register wieder herstellen
//---------------------------------------------------------------
@ Nil: xor eax,eax // Nicht gefunden
jmp @Ret // Return
//---------------------------------------------------------------
@Past: xor eax,eax // Nicht gefunden
jmp @Pop // Register wieder herstellen
//---------------------------------------------------------------
@ End: add esp,4 // Stack bereinigen
@Pop: pop esi // ESI wieder herstellen
pop edi // EDI wieder herstellen
pop ebx // EBX wieder herstellen
@Ret:
end;
{$ENDIF}
Delphi-Quellcode:
{$IFDEF CPUX64}
{------------------------------------------------------------------------------}
{ StrPos 64Bit }
{ Prüft, ob SearchFor in SearchIn innerhalb des Bereiches First..Last }
{ vorkommt und gibt die gefundene Position. bzw 0 für 'nicht gefunden' zurück. }
{ First<1 heißt ab Anfang von SearchIn suchen. }
{ Last<1 oder Last>Length(SearchIn) heißt bis Ende von SearchIn suchen. }
{------------------------------------------------------------------------------}
FUNCTION StrPos( const SearchFor,SearchIn: String; First,Last:NativeInt):Integer;
asm
// RCX=@SearchFor, RDX=@SearchIn, R8=First, R9=Last
test rcx,rcx
jz @ Nil // SearchFor leer
test edx,edx
jz @ Nil // SearchIn leer
dec r8 // First 0-Based
jge @FirstOk // First>=1
xor r8,r8
@FirstOK: movsx r10,dword[rdx-4] // Length(SearchIn)
test r9,r9
jle @LastOK // Last<=0 heißt bis Ende suchen
cmp r9,r10
jge @LastOK // Last>Length(SearchIn), bis Ende suchen
mov r10,r9 // Nur bis Last suchen
@LastOK: movsx r9,dword[rcx-4] // Length(SearchFor)
push rbx // RBX retten
lea rbx,[r8+r9]
cmp rbx,r10
jg @NotFound // First>Last oder First+Length(SearchFor)>Last
lea rax,[rcx+r9*2-2] // @SearchFor[Length(SearchFor)]
lea r11,[rdx+r10*2] // @SearchIn[Last+1]
lea rdx,[rdx+rbx*2-2] // @SearchIn[First+Length(SearchFor)-1]
lea r9,[r9*2-2] // 2*(Length(SearchFor)-1)
neg r9 // -(2*(Length(SearchFor)-1))
add r8,r8 // 2*(First-1)
sub r8,rdx // 2*(First-1)-@SearchIn[First+Length(SearchFor)-1]
mov cx,[rax] // Letztes Zeichen von SearchFor
// --------------------------------------------------------------
// RAX @SearchFor[Length(SearchFor)]
// RDX = Aktuelle Fundstelle für letztes Zeichen von SearchFor
// CX = Letztes Zeichen von SearchFor
// R8 = 2*(First-1)-@SearchIn[First+Length(SearchFor)-1]
// R9 = -(2*(Length(SearchFor)-1))
// R11 = Terminator
@Loop: cmp cx,[rdx] // Letzes Zeichen von SearchFor an EDX?
jz @Test0 // Ja, SearchIn auf voriges Zeichen
@AfterTest0: cmp cx,[rdx+2] // Letzes Zeichen von SearchFor an EDX+1 Zeichen
jz @TestT // J,
@AfterTestT: add rdx,8 // SearchIn+4 Zeichen
cmp rdx,r11 // SearchIn noch im zu durchsuchenden Bereich
jb @Continue // Ja
@EndLoop: add rdx,-4 // SearchIn-2 Zeichen
cmp rdx,r11 // SearchIn noch im zu durchsuchenden Bereich
jb @Loop // Ja
jmp @NotFound // Nicht gefunden
@Continue: cmp cx,[rdx-4] // Letzes Zeichen von SearchFor an EDX-2 Zeichen?
jz @Test2 // Ja, SearchIn -3 Zeichen
cmp cx,[rdx-2] // Letzes Zeichen von SearchFor an EDX-1 Zeichen?
jnz @Loop // Nein, nächste Position prüfen
@Test1: add rdx,2 // SearchIn + 1 Zeichen, durch folgende Adds - 2 Zeichen
@Test2: add rdx,-4 // SearchIn - 2 Zeichen, durch folgendes Add - 3 Zeichen
@Test0: add rdx,-2 // SearchIn - 1 Zeichen
@TestT: test r9,r9 // Hat SearchFor nur 1 Zeichen?
jz @Found // Ja, gefunden
mov r10,r9
@ String: mov ebx,[rax+r10] // 2 Zeichen aus SearchFor
cmp ebx,[rdx+r10+2] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn+4 Zeichen
cmp r10,-4 // Alle Zeichen gefunden?
jge @Found // Ja
mov ebx,[rax+r10+4] // Nächste 2 Zeichen aus SearchFor
cmp ebx,[rdx+r10+6] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn+4 Zeichen
add r10,8 // Zeichenzahl + 4 Zeichen
jl @ String // Nächste 4 Zeichen prüfen
//---------------------------------------------------------------
@Found: lea rax,[rdx+4] // Fundstelle
cmp rax,r11 // Im zu durchsuchenden Bereich?
ja @NotFound // Nein, nicht gefunden.
add rax,r8 // Endgültige Position in Bytes
shr rax,1 // Endgültige Position in Zeichen
pop rbx // RBX wieder herstellen
ret
//---------------------------------------------------------------
@ Nil: xor eax,eax
ret
@NotFound: //---------------------------------------------------------------
xor eax,eax // Nicht gefunden
pop rbx // RBX wieder herstellen
end;
{$ENDIF}
StrPosEx
Delphi-Quellcode:
{$IFDEF CPUX86}
{------------------------------------------------------------------------------}
{ StrPosEx 32bit }
{ Sucht alle Vorkommen von SearchFor in SearchIn und stellt die Positionen }
{ der Fundstellen in Positions. }
{ Es ist Sache der aufrufenden Stelle, sicherzustellen, daas Positions lang }
{ genug ist, alle Fundstellen zu speichern. }
{ Parameter }
{ SearchFor : String, nach dem gesucht wird. }
{ SearchIn : String, in dem gesucht wird. }
{ Positions : Array zur Speicherung der Fundstellen. }
{ Exceptions : Gibt an, in welchen Fällen Exceptions ausgelöst werden. }
{ 0 = Keine, -1 = Alle. }
{ Bit 0 = 1 : Wenn SearchFor leer ist. }
{ Bit 1 = 1 : Wenn SearchIn leer ist. }
{ Bit 2 = 1 : Wenn SearchFor länger ist, als SearchIn. }
{ Bit 3 = 1 : Wenn Positions nicht assigned ist. }
{ Bit 4 = 1 : Wenn Positions zu kurz ist. }
{ Wenn ein Fehler auftritt, und das korrespondierende Bit in }
{ Exceptions nicht gesetzt ist, werden folgende Fehlercodes }
{ zurückgegeben: }
{ -1 SearchFor leer. }
{ -2 SearchIn leer. }
{ -3 SearchFor länger als SearchIn. }
{ -4 Positions nicht assigned. }
{ -5 Positions zu kurz. }
{ Wenn kein Fehler auftritt, wird die Anzahl der Fundstellen zurückgegeben. }
{------------------------------------------------------------------------------}
FUNCTION StrPosEx( const SearchFor,SearchIn: String;
Positions:TIntegerDynArray; Exceptions:NativeInt=0):Integer;
const
sSearchForEmpty:String=' StrPosEx:'#13' SearchFor ist leer';
sSearchInEmpty:String=' StrPosEx:'#13' SearchIn ist leer';
sSearchForTooLong:String=' StrPosEx:'#13' Searchfo ist länger als SearchIn';
sPositionsEmpty:String=' StrPosEx:'#13' Positions ist nicht assigned';
sPositionsLength:String=' StrPosEx:'#13' Das Array "Positions" ist zu kurz '+
' um alle Fundstellen zu speichern';
pExClass:ExceptClass=( Exception);
asm
// EAX=@SearchFor, EDX=@SearchIn, ECX=Positions
// Register retten und Platz für lokale Variablen reservieren
push ebp
push ebx
push edi
push esi
sub esp,12 // Platz für 3 Integers
// Prüfen, ob SearchFor und SearchIn nicht leer sind
test eax,eax // SearchFor leer?
jz @SFNil // Ja, Fehlermedung
test edx,edx // SearchIn leer?
jz @SINil // Ja, Fehlermeldung
test ecx,ecx // Positions leer?
jz @PosNil // Ja, Fehlermeldung
// Längen von SearchFor und SearchIn laden und prüfen ob
// SearchFor nicht länger ist, als SearchIn
mov edi,[eax-4] // Length(SearchFor)
mov ebx,[edx-4] // Length(SearchIn)
cmp edi,ebx // SearchFor länger als SearchIn?
ja @SFTooLong // Ja, Fehlermeldung
cmp edi,1 // Hat SearchFor nur 1 Zeichen
je @Char // Ja
// Positions retten, Anzahl Fundstellen auf 0
mov [esp+8],ecx // Positions
mov [esp+4],0 // Anzahl Fundstellen
// Zeiger und Länge von SearchIn initialsieren
lea eax,[eax+edi*2-2] // EAX auf letztes Zeichen in SearchFor
lea ebp,[edx+ebx*2] // EBP hinter letztes Zeichen von SearchIn
lea edx,[edx+edi*2-2] // EDX auf Ende der ersten potentiellen Fundstelle
lea edi,[edi*2-2] // EDI = 2*(Length(SearchFor)-1)
neg edi // EDI = -(2*(Length(SearchFor)-1))
xor ecx,ecx
sub ecx,edx // ECX = -SearchIn[Length(SearchFor)-1]
mov [esp],ecx // Für spätere Positionsberechnung
// --------------------------------------------------------------
// EAX = Zeigt auf letztes Zeichen in SearchFor
// EDX = Zeigt auf Ende der nächsten potentiellen Fundstelle
// EBP = Zeigt hinter letztes Zeichen von SearchIn
// EDI = -(2*(Length(SearchFor)-1))
// [ESP-8] = Postions
// [ESP-4] = Anzahl Fundstellen
// [ESP] = -SearchIn[Length(SearchFor)-1]
@Start: mov cx,[eax] // letztes Zeichen von SearchFor
@Loop: cmp cx,[edx] // CX an [EDX]?
jz @Test0 // Ja, weitere Zeichen ab [EDX-1 Char] prüfen
@AfterTest0: cmp cx,[edx+2] // CX an [EDX + 1 Char]?
jz @TestT // Ja, weitere Zeichen ab [EDX] prüfen
@AfterTestT: add edx,8 // SearchIn + 4 Chars
cmp edx,ebp // SearchIn noch im zu durchsuchenden Bereich
jb @Continue // Ja
@EndLoop: add edx,-4 // SearchIn - 2 Chars
cmp edx,ebp // SearchIn noch im zu durchsuchenden Bereich
jb @Loop // Ja
jmp @NoFurther // Keine weiteren Fundstellen
@Continue: cmp cx,[edx-4] // CX an [EDX - 2 Chars]?
jz @Test2 // Ja, SearchIn - 3 Chars
cmp cx,[edx-2] // Letzes Zeichen von SearchFor an EDX-1 Zeichen?
jnz @Loop // Nein, nächste Position prüfen
@Test1: add edx,2 // SearchIn + 1 Char, durch folgende Adds - 2 Chars
@Test2: add edx,-4 // SearchIn - 2 Chars, durch folgendes Add - 3 Chars
@Test0: add edx,-2 // SearchIn - 1 Char
@TestT: test edi,edi // Alle Zeichen von SearchFor gefunden?
jz @Found // Ja, gefunden
mov esi,edi // -(2*(Length(SearchFor)-1))
@ String: mov ebx,[eax+esi] // 2 Zeichen aus SearchFor
cmp ebx,[edx+esi+2] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn + 4 Chars
cmp esi,-4 // Alle Zeichen gefunden?
jge @Found // Ja
mov ebx,[eax+esi+4] // Nächste 2 Zeichen aus SearchFor
cmp ebx,[edx+esi+6] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn + 4 Chars
add esi,8 // Zeichenzahl + 4 Chars
jl @ String // Nächste 4 Zeichen prüfen
//---------------------------------------------------------------
// Gefunden. EDX zeigt auf Fundstelle - 1 Zeichen
@Found: lea ecx,[edx+4] // Fundstelle + 1 Zeichen
cmp ecx,ebp // Im zu durchsuchenden Bereich?
ja @NoFurther // Nein, keine weiteren Fundstellen
add ecx,[esp] // Position in Bytes
shr ecx,1 // Position in Zeichen
mov esi,[esp+8] // Positions
mov ebx,[esp+4] // Bisherige Anzahl Fundstellen
cmp ebx,[esi-4] // Noch Platz in Positions?
jae @OutOfMem // Nein
mov [esi+ebx*4],ecx // Fundstelle speichern
inc ebx // Anzahl Fundstellen + 1
mov [esp+4],ebx // Anzahl Fundstellen speichern
// EDX auf nächste potentielle Fundstelle
mov esi,edi // -(2*(Length(SearchFor)-1))
neg esi // 2*(Length(SearchFor)-1)
lea edx,[edx+esi+4] // EDX=nächste potentielle Fundstelle
cmp edx,ebp // Noch im gültigen Bereich?
jb @Start // Ja, weiter suchen
jmp @NoFurther // Nein, keine weiteren Fundstellen
// --------------------------------------------------------------
// Suche nach nur einem Zeichen
// EAX = SearchFor
// EDX = SearchIn
// ECX = Positions
// EBX = Lenght(SearchIn)
@Char: mov ebp,ecx // Positions
xor ecx,ecx // Anzahl Fundstellen
lea edx,[edx+ebx*2] // Hinter letztes Zeichen von SearchIn
lea edi,[ebx+1] // für spötere Positionsermittlung
neg ebx
mov ax,[eax] // gesuchtes Zeichen
@CharLoop: cmp ax,[edx+ebx*2] // AX an aktueller Position?
jz @CharFound1 // Ja
cmp ax,[edx+ebx*2+2] // AX an nächster Position?
jz @CharFound2 // Ja
add ebx,2 // 2 Zeichen weiter
jl @CharLoop
jmp @NoFurtherC // Keine weiteren Fundstellen
// An [EDX+EBX*2] gefunden
@CharFound1: cmp ecx,[ebp-4] // Noch Platz in Positions?
jae @OutOfMem // Nein
lea esi,[edi+ebx] // Fundstelle
mov [ebp+ecx*4],esi // In Positions speichern
inc ecx // Anzahl Fundstellen
inc ebx // 1 Zeichen weiter
jl @CharLoop
jmp @NoFurtherC // Keine weiteren Fundstellen
// An [EDX+EBX*2+2] gefunden
@CharFound2: cmp ecx,[ebp-4] // Noch Platz in Positions?
jae @OutOfMem // Nein
lea esi,[edi+ebx+1] // Fundstelle * 2
mov [ebp+ecx*4],esi // In Positions speichern
inc ecx // Anzahl Fundstellen
add ebx,2 // 2 Zeichen weiter
jl @CharLoop
jmp @NoFurtherC // Keine weiteren Fundstellen
//---------------------------------------------------------------
// SearchFor ist leer
@SFNil: mov eax,sSearchForEmpty
mov ecx,1 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// SearchIn ist leer
@SINil: mov eax,sSearchInEmpty
mov ecx,2 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// SearchFor ist länger als SearchIn
@SFTooLong: mov eax,sSearchForTooLong
mov ecx,3 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// Positions ist nicht assigned
@PosNil: mov eax,sPositionsEmpty
mov ecx,4 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// Positions nicht lang genug um neue Fundstelle zu speichern
@OutOfMem: mov eax,sPositionsLength
mov ecx,5 // Fehlercode
jmp @ End // Fehlermeldung
//---------------------------------------------------------------
// Keine weiteren Fundstellen
@NoFurther: mov ecx,[esp+4] // Anzahl Fundstellen
@NoFurtherC: xor eax,eax // ´Kein Fehler
//---------------------------------------------------------------
// Stack bereinigen und Register restaurieren
@ End: add esp,12 // Stack bereinigen
pop esi // ESI wieder herstellen
pop edi // EDI wieder herstellen
pop ebx // EBX wieder herstellen
pop ebp // EBP wieder herstellen
//---------------------------------------------------------------
// Prüfen ob Fehler vorliegt und ggfs. Exception auslösen
test eax,eax // Fehler ?
jz @NoError // Nein, Anzahl Fundstellen zurückgeben
mov edx,1
shl edx,cl
neg ecx // Fehlercode
shr edx,1
test [ebp+8],edx // Exception werfen?
jz @NoError // Nein, nur Fehlercode zurückgeben
mov ecx,eax // Fehlertext
mov eax,pExClass // InstanceOrVMT
mov edx,1 // Alloc
call Exception.Create
call System.@RaiseExcept
//---------------------------------------------------------------
// Anzahl Fundstellen bzw. Fehlercode in Result
@NoError: mov eax,ecx // Anzahl Fundstellen bzw. FehlerCode
end;
{$ENDIF}
Delphi-Quellcode:
{$IFDEF CPUX64}
{------------------------------------------------------------------------------}
{ StrPosEx 64bit }
{ Sucht alle Vorkommen von SearchFor in SearchIn und stellt die Positionen }
{ der Fundstellen in Positions. }
{ Es ist Sache der aufrufenden Stelle, sicherzustellen, daas Positions lang }
{ genug ist, alle Fundstellen zu speichern. }
{ Parameter }
{ SearchFor : String, nach dem gesucht wird. }
{ SearchIn : String, inem gesucht wird. }
{ Positions : Array zur Speicherung der Fundstellen. }
{ Exceptions : Gibt an, in welchen Fällen Exceptions ausgelöst werden. }
{ 0 = Keine, -1 = Alle }
{ In der aktuellen Version ist das Werfen von Exceptions }
{ deaktiviert, weil der Code hier nicht funktioniert. }
{ In anderen Anwendungen funktioniert er. }
{ Bit 0 = 1 : Wenn SearchFor leer ist. }
{ Bit 1 = 1 : Wenn SearchIn leer ist. }
{ Bit 2 = 1 : Wenn SearchFor länger ist, als SearchIn. }
{ Bit 3 = 1 : Wenn Positions nicht assigned ist. }
{ Bit 4 = 1 : Wenn Positions zu kurz ist. }
{ Wenn ein Fehler auftritt, und das korrespondierende Bit in }
{ Exceptions nicht gesetzt ist, werden folgende Fehlercodes }
{ zurückgegeben: }
{ -1 SearchFor leer. }
{ -2 SearchIn leer. }
{ -3 SearchFor länger als SearchIn. }
{ -4 Positions nicht assigned. }
{ -5 Positions zu kurz. }
{ Wenn kein Fehler auftritt, wird die Anzahl der Fundstellen zurückgegeben. }
{------------------------------------------------------------------------------}
FUNCTION StrPosEx( const SearchFor,SearchIn: String;
Positions:TIntegerDynArray; Exceptions:NativeInt=0):Integer;
const
sSearchForEmpty:String=' StrPosEx:'#13' SearchFor ist leer';
sSearchInEmpty:String=' StrPosEx:'#13' SearchIn ist leer';
sSearchForTooLong:String=' StrPosEx:'#13' Searchfo ist länger als SearchIn';
sPositionsEmpty:String=' StrPosEx:'#13' Positions ist nicht assigned';
sPositionsLength:String=' StrPosEx:'#13' Das Array "Positions" ist zu kurz '+
' um alle Fundstellen zu speichern';
pExClass:ExceptClass=( Exception);
asm
// RCX=@SearchFor, RDX=@SearchIn, R8=Positions, R9=Exceptions
// Exceptions = 0 (keine Exceptions) setzen, weil das hier
// nicht funktioniert (In anderen Projektion funktionierts).
xor r9,r9 // Keine Exceptions
// Register retten
push rbp
push rbx
push rdi
push rsi
push r12
// Prüfen, ob SearchFor und SearchIn nicht leer sind
test rcx,rcx // SearchFor leer?
jz @SFNil // Ja, Fehlermedung
test rdx,rdx // SearchIn leer?
jz @SINil // Ja, Fehlermeldung
test r8,r8 // Positions assigned?
jz @PosEmpty // Nein, Fehlermeldung
// Längen von Positons, SearchFor und SearchIn laden und
// prüfen ob SearchFor nicht länger ist, als SearchIn
movsx rdi,dword[rcx-4] // Length(SearchFor)
movsx rbx,dword[rdx-4] // Length(SearchIn)
cmp edi,ebx // SearchFor länger als SearchIn?
ja @SFTooLong // Ja, Fehlermeldung
mov r11,[r8-8] // Length Positions
xor r10,r10 // Anzahl Fundstellen auf 0
cmp edi,1 // Hat SearchFor nur 1 Zeichen
je @Char // Ja
// Zeiger und Länge von SearchIn initialsieren
lea rax,[rcx+rdi*2-2] // RAX auf letztes Zeichen in SearchFor
lea rbp,[rdx+rbx*2] // RBP hinter letztes Zeichen von SearchIn
lea rdx,[rdx+rdi*2-2] // RDX auf Ende der ersten potentiellen Fundstelle
lea rdi,[rdi*2-2] // RDI = 2*(Length(SearchFor)-1)
neg rdi // RDI = -(2*(Length(SearchFor)-1))
xor r12,r12
sub r12,rdx // R12 = -SearchIn[Length(SearchFor)-1]
// --------------------------------------------------------------
// RAX = Zeigt auf letztes Zeichen in SearchFor
// RDX = Zeigt auf Ende der nächsten potentiellen Fundstelle
// RBP = Zeigt hinter letztes Zeichen von SearchIn
// RDI = -(2*(Length(SearchFor)-1))
// R8 = Postions
// R9 = Exceptions
// R10 = Anzahl Fundstellen
// R11 = Length(Positions)
// R12 = -SearchIn[Length(SearchFor)-1]
// Für Ermittlung der Positionen von Fundstellen
@Start: mov cx,[rax] // letztes Zeichen von SearchFor
@Loop: cmp cx,[rdx] // CX an [EDX]?
jz @Test0 // Ja, weitere Zeichen ab [EDX-1 Char] prüfen
@AfterTest0: cmp cx,[rdx+2] // CX an [EDX + 1 Char]?
jz @TestT // Ja, weitere Zeichen ab [EDX] prüfen
@AfterTestT: add rdx,8 // SearchIn + 4 Chars
cmp rdx,rbp // SearchIn noch im zu durchsuchenden Bereich
jb @Continue // Ja
@EndLoop: add rdx,-4 // SearchIn - 2 Chars
cmp rdx,rbp // SearchIn noch im zu durchsuchenden Bereich
jb @Loop // Ja
jmp @NoFurther // Keine weiteren Fundstellen
@Continue: cmp cx,[rdx-4] // CX an [EDX - 2 Chars]?
jz @Test2 // Ja, SearchIn - 3 Chars
cmp cx,[rdx-2] // Letzes Zeichen von SearchFor an EDX-1 Zeichen?
jnz @Loop // Nein, nächste Position prüfen
@Test1: add rdx,2 // SearchIn + 1 Char, durch folgende Adds - 2 Chars
@Test2: add rdx,-4 // SearchIn - 2 Chars, durch folgendes Add - 3 Chars
@Test0: add rdx,-2 // SearchIn - 1 Char
@TestT: test rdi,rdi // Alle Zeichen von SearchFor gefunden?
jz @Found // Ja, gefunden
mov rsi,rdi // -(2*(Length(SearchFor)-1))
@ String: mov ebx,[rax+rsi] // 2 Zeichen aus SearchFor
cmp ebx,[rdx+rsi+2] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn + 4 Chars
cmp rsi,-4 // Alle Zeichen gefunden?
jge @Found // Ja
mov ebx,[rax+rsi+4] // Nächste 2 Zeichen aus SearchFor
cmp ebx,[rdx+rsi+6] // In SearchIn?
jnz @AfterTestT // Nein, SearchIn + 4 Chars
add rsi,8 // Zeichenzahl + 4 Chars
jl @ String // Nächste 4 Zeichen prüfen
//---------------------------------------------------------------
// Gefunden. RDX zeigt auf Fundstelle - 1 Zeichen
@Found: lea rsi,[rdx+4] // Fundstelle + 1 Zeichen
cmp rsi,rbp // Im zu durchsuchenden Bereich?
ja @NoFurther // Nein, keine weiteren Fundstellen
add rsi,r12 // Position in Bytes
shr rsi,1 // Position in Zeichen
cmp r10,r11 // Noch Platz in Positions?
jae @OutOfMem // Nein
mov [r8+r10*4],esi // Fundstelle speichern
inc r10 // Anzahl Fundstellen + 1
// RDX auf nächste potentielle Fundstelle
mov rsi,rdi // -(2*(Length(SearchFor)-1))
neg rsi // 2*(Length(SearchFor)-1)
lea rdx,[rdx+rsi+4] // EDX=nächste potentielle Fundstelle
cmp rdx,rbp // Noch im gültigen Bereich?
jb @Loop // Ja, weiter suchen
jmp @NoFurther // Nein, keine weiteren Fundstellen
// --------------------------------------------------------------
// Suche nach nur einem Zeichen
// RCX = SearchFor
// RDX = SearchIn
// RBX = Lenght(SearchIn)
// R8 = Positions
// R9 = Exceptions
// R10 = Anzahl Fundstellen
// R11 = Length(Positions)
@Char: lea rdx,[rdx+rbx*2] // Hinter letztes Zeichen von SearchIn
lea rdi,[rbx+1] // für spätere Positionsermittlung
neg rbx
mov ax,[rcx] // gesuchtes Zeichen
@CharLoop: cmp ax,[rdx+rbx*2] // AX an aktueller Position?
jz @CharFound1 // Ja
cmp ax,[rdx+rbx*2+2] // AX an nächster Position?
jz @CharFound2 // Ja
add rbx,2 // 2 Zeichen weiter
jl @CharLoop
jmp @NoFurther // Keine weiteren Fundstellen
// An [EDX+EBX*2] gefunden
@CharFound1: cmp r10,r11 // Noch Platz in Positions?
jae @OutOfMem // Nein
lea rsi,[rdi+rbx] // Fundstelle
mov [r8+r10*4],esi // In Positions speichern
inc r10 // Anzahl Fundstellen
inc rbx // 1 Zeichen weiter
jl @CharLoop // Weiter, solange negativ
jmp @NoFurther // Keine weiteren Fundstellen
// An [EDX+EBX*2+2] gefunden
@CharFound2: cmp r10,r11 // Noch Platz in Positions?
jae @OutOfMem // Nein
lea rsi,[rdi+rbx+1] // Fundstelle
mov [r8+r10*4],esi // In Positions speichern
inc r10 // Anzahl Fundstellen
add rbx,2 // 2 Zeichen weiter
jl @CharLoop // Weiter, solange negativ
jmp @NoFurther // Keine weiteren Fundstellen
//---------------------------------------------------------------
// SearchFor ist leer
@SFNil: mov r8,sSearchForEmpty
mov ecx,1 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// SearchIn ist leer
@SINil: mov r8,sSearchInEmpty
mov ecx,2 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// SearchFor ist länger als SearchIn
@SFTooLong: mov r8,sSearchForTooLong
mov ecx,3 // Fehlercode
jmp @ End
//---------------------------------------------------------------
// Positions ist nicht assigned
@PosEmpty: mov r8,sPositionsEmpty
mov ecx,4 // Fehlercode
jmp @ End // Fehlermeldung
//---------------------------------------------------------------
// Positions nicht lang genug um neue Fundstelle zu speichern
@OutOfMem: mov r8,sPositionsLength
mov ecx,5 // Fehlercode
jmp @ End // Fehlermeldung
//---------------------------------------------------------------
// Keine weiteren Fundstellen
@NoFurther: xor r8,r8 // ´Kein Fehler
mov rcx,r10 // Anzahl Fundstellen
//---------------------------------------------------------------
// Register restaurieren
@ End: pop r12 // R12 wieder herstellen
pop rsi // RSI wieder herstellen
pop rdi // RDI wieder herstellen
pop rbx // RBX wieder herstellen
pop rbp // RBP wieder herstellen
//---------------------------------------------------------------
// Prüfen ob Fehler vorliegt und ggfs. Exception auslösen
test r8,r8 // Fehler ?
jz @NoError // Nein, Anzahl Fundstellen zurückgeben
mov edx,1
shl edx,cl
neg ecx // Fehlercode
shr edx,1
test r9d,edx // Exception werfen?
jz @NoError // Nein, nur Fehlercode zurückgeben
// Exception auslösen
push rcx // Fehlercode retten
push rbp
sub rsp,$20
mov rbp,rsp
mov rcx,pExClass // InstanceOrVMT
mov dl,$01 // Alloc
call Exception.Create
mov rcx,rax
call System.@RaiseExcept
add rsp,$20
pop rbp
pop rcx // Fehlercode
//---------------------------------------------------------------
// Anzahl Fundstellen bzw. Fehlercode in Result
@NoError: mov eax,ecx // Anzahl Fundstellen bzw. FehlerCode
end;
{$ENDIF}
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
|