I have written this procedure to do it, but it would.be good if there is a shorter alternative. I've tried to reduce the code to a minimum. Am I missing an easier way? Thanks.
Code: Select all
EnableExplicit
; **
; ** Find position of n-th occurrence of a sub-string in a string - for example the 3rd "/" in 1/2/3/4/5 would be 6
; **
Procedure.q Find_String_Index(string.s, find.s, index.q)
Define findpos.q ; Running FindString() result for each occurrence
Define foundpos.q ; Found position of n-th occurrence
Define findcnt.q ; Running counter of found sub-string
Define stpos.q ; Running start position for FindString()
Define done.b ; Loop exit indicator
If index.q > 0 ; Index.q value must be at least 1
stpos.q = 1 ; Start at position 1 of string to be searched
done.b = #False
While Not(done.b) ; Loop until exit flag set
findpos.q = FindString(string.s, find.s, stpos.q) ; Find sub-string with rolling start position stpos
If findpos.q ; Found sub-string with position findpos.q
findcnt.q + 1 ; Increment our occurrence counter
stpos.q = findpos.q + 1 ; Set next start position one char on from found pos.
If findcnt.q = index.q
foundpos.q = findpos.q ; Set the position of the final 'index' occurrence
done.b = #True ; Nothing more to do
EndIf
Else
done.b = #True ; FindString() didn't find, so nothing more to do
EndIf
Wend
EndIf
ProcedureReturn foundpos.q ; Return character position where this count found
EndProcedure
Define string.s = "words()are()separated()by()bracketed()delimiters()like()this."
Debug Find_String_Index(string.s, "()", 2) ; <---- Will return 11
Debug Find_String_Index(string.s, "()", 5) ; <---- Will return 37
Debug Find_String_Index(string.s, "()", 7) ; <---- Will return 55
Debug Find_String_Index(string.s, "()", 8) ; <---- Will return 0 since there are only 7 sub-strings
Debug Find_String_Index(string.s, "()", 0) ; <---- Test nonsense value, will return 0
Debug ""
string.s = "words/are/separated/by/bracketed/delimiters/like/this."
Debug Find_String_Index(string.s, "/", 2) ; <---- Will return 10
Debug Find_String_Index(string.s, "/", 5) ; <---- Will return 33
Debug Find_String_Index(string.s, "/", 7) ; <---- Will return 49
Debug Find_String_Index(string.s, "/", 8) ; <---- Will return 0 since there are only 7 sub-strings
Debug Find_String_Index(string.s, "/", 0) ; <---- Test nonsense value, will return 0