Einzelnen Beitrag anzeigen

Amateurprofi

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

AW: Alternative zu PosEx

  Alt 23. Nov 2024, 13:33
Hier sind auch die 64bit-Versionen von StrPos und StrPosEx.
Der Vollständigkeit halber und wegen marginaler Änderungen auch noch mal die 32bit-Versionen.

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)
               add r8,r9 // First+Length(SearchFor)-1
               cmp r8,r10
               jg @Nil // First>Last oder First+Length(SearchFor)>Last
               push rbx // RBX retten
               lea rax,[rcx+r9*2-2] // @SearchFor[Length(SearchFor)]
               lea r11,[rdx+r10*2] // @SearchIn[Last+1]
               lea rdx,[rdx+r8*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....
  Mit Zitat antworten Zitat