This is a pure AppleScript question, although it stemmed from a Keyboard Maestro forum post I was working on.
I recall one or two members here are particularly apt at formulating and/or debugging recursive functions. If anyone can tag an appropriate person for their attention, that would be helpful.
Objective:
AppleScript's offset
command returns the index (character position) of the first occurrence (left-to-right) of a substring within a string (or 0
if not found). I'm redefining it to perform this function recursively, so that it returns a list of indices of all occurrences of a substring within a string.
The syntax for offset
is:
offset of %substring% in %string%
This is a specific objective, outwith any other methods of achieving the same action performed on a string (I'm sure most or all of us here can throw together a simple handler that indexes substrings):
`IndexOf` AppleScript handlers (iterative & recursive)
script iterative
on indexOf(x, L)
local x, L
if L = {} or (x is not in L) then return 0
if L's class = text then set L to L's characters
script
property array : L
end script
tell the result's array
repeat with i from 1 to its length
if x ≠ its item i then
set its item i to null
else
set its item i to i
end if
end repeat
its numbers
end tell
end indexOf
end script
script recursive
on indexOf(x, L)
local x, L
if L = {} or (x is not in L) then return {}
if L's class = text then set L to L's characters
script
property array : L
end script
tell the result's array
set [x0, xN] to its [last item, ¬
reverse of rest of reverse]
if x = x0 then return my indexOf(x, xN) ¬
& (its length)
end tell
indexOf(x, xN)
end indexOf
end script
iterative's indexOf(8, {1, 2, 4, 8, 2, 4, 6, 8, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
--> {4, 8, 11}
recursive's indexOf(8, {1, 2, 4, 8, 2, 4, 6, 8, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
--> {4, 8, 11}
iterative's indexOf("e", "Keyboard Maestro") --> {2, 12}
recursive's indexOf("e", "Keyboard Maestro") --> {2, 12}
Why?
I did have a reason and then forgot what that reason was, and merely became fixated on the objective. It's now more about solving the problem than producing anything intrinsically of value.
Initial iterative implementation
After some failed attempts to construct a recursive routine, I implemented an iterative one to visualise the function's actions:
on offset of t in str
local t, str
set [i, j] to [1, 0]
set array to {j}
repeat
set i to current application's (offset of t ¬
in (text (j + 1) thru -1 of str))
if i = 0 then exit repeat
set j to (the array's last item) + i
set the end of the array to j
end repeat
rest of the array
end offset
offset of "*" in "12*45678*0*BC*EF"
--> {3, 9, 11, 14}
Failed recursive attempt (final of many)
on offset of t in str
local t, str
set i to (current application's (offset of t in str))
if i = 0 then return {str's length}
set j to offset of t in (text (i + 1) thru -1 of str)
j & (i + (j's item -1))
end offset
offset of "*" in "12*45678*0*BC*EF"
--> {2, 5, 7, 13, 16}
I don't like admitting defeat with things like this, but I am.