stringvb.netsplitindexofinstr

How to get string positions And Length by multi-split filter


enter image description here

I am trying to create what I expect from the subroutine (GetAllPosition). I don't know where to use RsultOfPostionAndLength in the code to get the expected output

My expectation of the output for (RsultOfPostionAndLength ):

MultiSplit' For {"C", "B", "A"} is: 55-5 '}666[' 61-5']777(' 67-3')8[' 71-6']hhhy('

MultiSplit' For {"A", "B", "C"} is: 27-6 ']1111{' 34-4'}22(' 39-7')33333{' 47-3'}4{' 51-3 '}5{' 55-5'}666[' 78-4')99{' 83-5'}999['

    Dim RsultOfPostionAndLength As List(Of String) 'Pattern is Position of String And Length Of Find
    '  'MultiSplit' For {"C", "B", "A"} is:  55-5 '}666['  61-5']777('    67-3')8['  71-6']hhhy('
    '  'MultiSplit' For {"A", "B", "C"} is:  27-6 ']1111{'  34-4'}22('    39-7')33333{'  47-3'}4{' 51-3 '}5{' 55-5'}666[' 78-4')99{'  83-5'}999['
   

 Sub Setup()
        Dim inString As String = "}666[]777([}666[]777(]00[A]1111{C}22(B)33333{C}4{C}5{C}666[A]777(B)8[A]hhhy(B)99{C}999[A]101010}666[]777("
        Dim MultiSplit As String() = {"C", "B", "A"}
        GetAllPosition(1, inString.Length, inString, MultiSplit, 0)
    End Sub

 Sub GetAllPosition(LastIdx As Integer, LastLen As Integer, inString As String, MultiSplit As String(), Level As Integer)
        Dim spl As String() = Split(inString, ",")
        Dim body As String = Mid(inString, LastIdx, LastLen)
        'Dim LastIdx As Integer = spl(0)
        Dim results As New List(Of String)
        Dim Find As String = MultiSplit(Level)
        Dim last As Integer = LastIdx
        Dim index As Integer = -1
        Do Until body.Length <= index
            index = body.IndexOf(Find, index + 1)
            If index = -1 AndAlso body.Length > last Then
                index = body.Length
            End If
            Dim lenTexxt As Integer = Math.Abs(last - index) + 1
            Dim part1 As String = Mid(body, last, lenTexxt)
            Dim part As String = Mid(inString, last, lenTexxt)
            Dim b As Boolean = MultiSplit.Skip(Level + 1).All(Function(c) part.IndexOf(c, comparisonType:=StringComparison.OrdinalIgnoreCase) > -1)
            If b Then
                results.Add(last & "," & lenTexxt & "," & part)
            End If
            last = index + 2
        Loop
        Level += 1
        For Each g In results
            Dim spl2 As String() = Split(g, ",")
            GetAllPosition(spl2(0), spl2(1), inString, MultiSplit, Level)
        Next
    End Sub

Solution

  • You are trying a recursive approach, which is a good thing to do in this situation. My solution uses a Structure to store the results.

    Structure ResultItem
        Public Value As String
        Public Position As Integer
        Public Length As Integer
    
        Public Overrides Function ToString() As String
            Return $"{Position}-{Length} ""{Value}"""
        End Function
    End Structure
    

    We have to split by the separator corresponding to the current level ("A", "B" or "C"). The last level must be treated differently to end the recursion and also because we do not have to test whether the next level separator is contained.

    Sub Test()
        Dim inString As String = "}666[]777([}666[]777(]00[A]1111{C}22(B)33333{C}4{C}5{C}666[A]777(B)8[A]hhhy(B)99{C}999[A]101010}666[]777("
        Dim MultiSplit As String() = {"A", "B", "C"}
    
        Dim result As List(Of ResultItem) = AllPositions(inString, 0, MultiSplit, 0)
    
        For Each r As ResultItem In result
            Console.WriteLine(r)
        Next
    End Sub
    
    Public Function AllPositions(input As String, index As Integer, separators As String(), level As Integer) As List(Of ResultItem)
        Dim separator As String = separators(level)
        Dim parts As String() =
            Split(input, separator, Compare:=CompareMethod.Text) 'Ignores case
    
        Dim result = New List(Of ResultItem)()
        If level = separators.Length - 1 Then
            For Each part As String In parts
                Dim item = New ResultItem With {
                    .Value = part,
                    .Position = index,
                    .Length = part.Length
                }
                result.Add(item)
                index += part.Length + separator.Length
            Next
        Else
            Dim nextSeparator As String = separators(level + 1)
            For Each part As String In parts
                If part.Contains(nextSeparator, StringComparison.OrdinalIgnoreCase) Then
                    result.AddRange(AllPositions(part, index, separators, level + 1))
                End If
                index += part.Length + separator.Length
            Next
        End If
        Return result
    End Function
    

    Output of my console test:

    26-6 "]1111{"
    33-4 "}22("
    38-7 ")33333{"
    46-3 "}4{"
    50-3 "}5{"
    54-5 "}666["
    77-4 ")99{"
    82-5 "}999["