I would like to write a IndexOfAll function that must return the indices of all the occurrences of the given pattern found within that string.
The function has a startIndex and count parameters like one of the overloads of the built-in .NET function: string.IndexOf()
The count parameter, like in the built-in .NET function, it will represent the number / max. range of character positions to examine in the source string.
The problem is that I'm breaking my head trying to figure how to properly calculate the value for count. Probably this would be a very easy mathematical calculation but I don't get it, and I end up with negative numeric values for count (that's why I have a try/catch block in the code below, because due the wrong count value calculation I end getting a exception)...
So, how I calculate the count value?. This is what I have:
Public Function IndexOfAll(str As String,
find As String,
startIndex As Integer,
count As Integer,
comparisonType As StringComparison) As Integer()
Dim indices As New Collection(Of Integer)()
Dim index As Integer = str.IndexOf(find, startIndex, count, comparisonType)
indices.Add(index)
Do
startIndex = index 1
count = ???
' Console.WriteLine($"idx {index}, start {startIndex}, count {count}")
Try
index = str.IndexOf(find, startIndex, count, comparisonType)
indices.Add(index)
Catch ex As Exception
Exit Do
End Try
Loop
Return indices.ToArray()
End Function
NOTE: calling the built-in string.IndexOf() function it's fine for me, at least for now. I don't pretend to try implement complex string parsing algorithms (that maybe could be broken) to do exact the same as string.IndexOf() but with just in few less seconds or milliseconds depending on how large the string is.
CodePudding user response:
Find the end index (startIndex count), and then subtract the new start index.
You'll also want to check the index before adding it to the list.
Public Function IndexOfAll(
str As String,
find As String,
startIndex As Integer,
count As Integer,
comparisonType As StringComparison) As Integer()
Dim endIndex As Integer = startIndex count
Dim indices As New Collection(Of Integer)()
Dim index As Integer = str.IndexOf(find, startIndex, count, comparisonType)
Do While index <> -1
indices.Add(index)
startIndex = index 1
count = endIndex - startIndex
index = str.IndexOf(find, startIndex, count, comparisonType)
Loop
Return indices.ToArray()
End Function
CodePudding user response:
It can be done with a LINQ one-liner
Public Function IndexOfAll(source As String, find As String, startIndex As Integer, count As Integer, comparisonType As StringComparison) As IEnumerable(Of Integer)
Return source.
Skip(startIndex).
Take(source.Length - find.Length - startIndex 1).
Select(Function(c, i) source.IndexOf(find, i startIndex, count, comparisonType)).
Where(Function(i) i >= 0)
End Function
The purpose of Skip and Take is to look at only those first characters where we will start comparison. The Select takes the character and its index. But since we Skip, we need to add the startIndex back within IndexOf. Select then returns the character position. Where returns only those character positions which are non negative.
