Next Position of a sub-string in a string (Views: 308)
Problem/Question/Abstract: The Pos funciton of Delphi returns the first occurence of a sub string within a string, only. How to get the positions of the next occurences? Answer: Solve 1: This solution was developed using Borland Delphi 5 Service Pack 1. It is based upon the Pos algorithm delivered by Borland within the Systems unit, completely written in Assembler. !!!It might work with other versions of Borland Delphi (3.x, 4.x, 5.0) but has not been tested on them!!! The syntax is similar to the syntax of the Pos function supplied by Delphi: function NextPos(Substr: string; S: string; LastPos: DWORD = 0): DWORD; NextPos returns the index value of the first character in a specified substring that occurs in a given string starting after the index value supplied by LastPos. LastPos may be omitted. Note: As LastPos you should pass the position of the last occurence, not last position + 1. Just for convinience. Here the commented Code: function NextPos(SubStr: AnsiString; Str: AnsiString; LastPos: DWORD = 0): DWORD; type StrRec = packed record allocSiz: Longint; refCnt: Longint; length: Longint; end; const skew = sizeof(StrRec); asm // Search-String passed? TEST EAX,EAX JE @@noWork // Sub-String passed? TEST EDX,EDX JE @@stringEmpty // Save registers affected PUSH ECX PUSH EBX PUSH ESI PUSH EDI // Load Sub-String pointer MOV ESI, EAX // Load Search-String pointer MOV EDI, EDX // Save Last Position in EBX MOV EBX, ECX // Get Search-String Length MOV ECX, [EDI - skew].StrRec.length // subtract Start Position SUB ECX, EBX // Save Start Position of Search String to return PUSH EDI // Adjust Start Position of Search String ADD EDI, EBX // Get Sub-String Length MOV EDX, [ESI - skew].StrRec.length // Adjust DEC EDX // Failed if Sub-String Length was zero JS@@fail // Pull first character of Sub-String for SCASB function MOV AL, [ESI] // Point to second character for CMPSB function INC ESI // Load character count to be scanned SUB ECX, EDX // Failed if Sub-String was equal or longer than Search-String JLE@@fail @@loop: // Scan for first matching character REPNE SCASB // Failed, if none are matching JNE@@fail // Save counter MOV EBX, ECX PUSH ESI PUSH EDI // load Sub-String length MOV ECX, EDX // compare all bytes until one is not equal REPE CMPSB // restore counter POP EDI POP ESI // all byte were equal, search is completed JE@@found // restore counter MOV ECX, EBX // continue search JMP@@loop @@fail: // saved pointer is not needed POP EDX xor EAX, EAX JMP@@exit @@stringEmpty: // return zero - no match xor EAX, EAX JMP@@noWork @@found: // restore pointer to start position of Search-String POP EDX // load position of match MOV EAX, EDI // difference between position and start in memory is // position of Sub SUB EAX, EDX @@exit: // restore registers POP EDI POP ESI POP EBX POP ECX @@noWork: end; Solve 2: PosEx function: function PosEx(SubStr: string; s: string; Index: DWord): DWord; var I: Integer; begin I := Pos(SubStr, Copy(s, Index, Length(s) - Index + 1)); if I <> 0 then I := I + Index - 1; Result := I; end; The prarameter Index is the position you want to begin to search substr in s. |