Author: Daniel Wischnewski
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:
1 function NextPos(SubStr: AnsiString; Str: AnsiString; LastPos: DWORD
2 = 0): DWORD;
3 type
4 StrRec = packed record
5 allocSiz: Longint;
6 refCnt: Longint;
7 length: Longint;
8 end;
9 const
10 skew = sizeof(StrRec);
11
12 asm
13 // Search-String passed?
14 TEST EAX,EAX
15 JE @@noWork
16
17 // Sub-String passed?
18 TEST EDX,EDX
19 JE @@stringEmpty
20
21 // Save registers affected
22 PUSH ECX
23 PUSH EBX
24 PUSH ESI
25 PUSH EDI
26
27 // Load Sub-String pointer
28 MOV ESI, EAX
29 // Load Search-String pointer
30 MOV EDI, EDX
31 // Save Last Position in EBX
32 MOV EBX, ECX
33 // Get Search-String Length
34 MOV ECX, [EDI - skew].StrRec.length
35 // subtract Start Position
36 SUB ECX, EBX
37 // Save Start Position of Search String to return
38 PUSH EDI
39 // Adjust Start Position of Search String
40 ADD EDI, EBX
41 // Get Sub-String Length
42 MOV EDX, [ESI - skew].StrRec.length
43 // Adjust
44 DEC EDX
45 // Failed if Sub-String Length was zero
46 JS@@fail
47 // Pull first character of Sub-String for SCASB function
48 MOV AL, [ESI]
49 // Point to second character for CMPSB function
50 INC ESI
51 // Load character count to be scanned
52 SUB ECX, EDX
53 // Failed if Sub-String was equal or longer than Search-String
54 JLE@@fail
55 @@loop:
56 // Scan for first matching character
57 REPNE SCASB
58 // Failed, if none are matching
59 JNE@@fail
60 // Save counter
61 MOV EBX, ECX
62 PUSH ESI
63 PUSH EDI
64 // load Sub-String length
65 MOV ECX, EDX
66 // compare all bytes until one is not equal
67 REPE CMPSB
68 // restore counter
69 POP EDI
70 POP ESI
71 // all byte were equal, search is completed
72 JE@@found
73 // restore counter
74 MOV ECX, EBX
75 // continue search
76 JMP@@loop
77 @@fail:
78 // saved pointer is not needed
79 POP EDX
80 xor EAX, EAX
81 JMP@@exit
82 @@stringEmpty:
83 // return zero - no match
84 xor EAX, EAX
85 JMP@@noWork
86 @@found:
87 // restore pointer to start position of Search-String
88 POP EDX
89 // load position of match
90 MOV EAX, EDI
91 // difference between position and start in memory is
92 // position of Sub
93 SUB EAX, EDX
94 @@exit:
95 // restore registers
96 POP EDI
97 POP ESI
98 POP EBX
99 POP ECX
100 @@noWork:
101 end;
Solve 2:
102 PosEx function:
103
104 function PosEx(SubStr: string; s: string; Index: DWord): DWord;
105 var
106 I: Integer;
107 begin
108 I := Pos(SubStr, Copy(s, Index, Length(s) - Index + 1));
109 if I <> 0 then
110 I := I + Index - 1;
111 Result := I;
112 end;
The prarameter Index is the position you want to begin to search substr in s.
|