A recursive solution makes sense here, so long as you're not expecting to look for the 10,000th match or some such. Here's one approach:
const indexOfAny = (string, substrings, pos = 0) => {
const positions = substrings .map (ss => string .indexOf (ss, pos))
.filter (n => n > -1)
return positions .length == 0 ? -1 : Math .min (... positions)
}
const nthOfAny = (n, string, subtrings, pos = 0) => {
const first = indexOfAny (string, substrings, pos)
return n <= 1
? first
: first == -1
? -1
: nthOfAny (n - 1, string, substrings, 1 + indexOfAny (string, substrings, pos))
}
const string = 'A <br> B <br/> C <br /> D <br/>'
const substrings = ['<br>','<br/>','<br />']
console. log (
nthOfAny (2, string, substrings)
)
console.log (
[1, 2, 3, 4, 5, 6] .map (n => nthOfAny (n, string, substrings))
)
We first define indexOfAny
which takes a string, an array of substrings to search for, and (optionally) an initial position, and it returns the position of the first one found, or -1
if none is found.
Then nthOfAny
takes an ordinal (1
for first, 2
for second, etc.) and the same arguments as above and recursively finds that one by increasing pos
to the previously found one and decreasing n
until it hits a base case that just returns the result of indexOfAny
.
There is a fair bit of extra complexity meant to use -1
to signal that nothing isn't found, to match indexOf
. A simpler solution would return Infinity
for that case:
const indexOfAny = (string, substrings, pos = 0) =>
Math.min (
... substrings .map (ss => string .indexOf (ss, pos)) .filter (n => n > -1)
)
const nthOfAny = (n, string, subtrings, pos = 0) =>
n <= 1
? indexOfAny (string, substrings, pos)
: nthOfAny (n - 1, string, substrings, 1 + indexOfAny (string, substrings, pos))
i guess and so it result with the end of the string. If you do like var index = string.split('
', 2).join('
').length;result would be 26 that is the index of the second
which is actually there – Sasha Grievus Dec 07 '20 at 13:37