简体   繁体   中英

Parsing a Multi - Tree from a string

I am trying to parse a Multi - Tree from a String.


The Syntax :

root (Tree,Tree,Tree ...) =

在此处输入图片说明

For example :

1(2,3,4(5,3),4(7,8,5)) =

在此处输入图片说明


I figured out how to parse binary trees from strings:

My Code :

Public Class Tree
Public l As Tree = Nothing
Public r As Tree = Nothing
Public value As String
Public Sub New(ByVal Str As String)
    If Str = "" Then Throw New Exception("Input String is Nothing ("""")")
    Dim Error_Report As String = RunCheck(Str)
    If Not Error_Report = "" Then Throw New Exception(Error_Report)
    If Str.Contains("(") Then
        Try
            value = Str.Substring(0, Str.IndexOf("("))
            BulidTreeByInTo(Str.Substring(Str.IndexOf("(") + 1, Str.Length - 2 - Str.IndexOf("(")), l, r)
        Catch ex As Exception
            Throw ex
        End Try
    Else
        value = Str
    End If
End Sub
Private Function RunCheck(ByVal str As String) As String
    Dim Open_Close As Integer = 0
    For i = 0 To str.Length - 1 Step 1
        If str(i).ToString = "(" Then
            Open_Close += 1
        ElseIf str(i).ToString = ")" Then
            Open_Close -= 1
        End If
        If i >= 1 Then
            If (str(i - 1).ToString = ")" And str(i).ToString = "(") Or (str(i - 1).ToString = "(" And str(i).ToString = ")") Then
                Return "Error in bracket At Index " & i
            End If
            If (str(i - 1).ToString = "(" And str(i).ToString = ",") Or (str(i - 1).ToString = "," And str(i).ToString = ")") Or (str(i - 1).ToString = "," And str(i).ToString = "(") Or (str(i - 1).ToString = "," And str(i).ToString = ",") Then
                Return "Error in Comma At Index " & i
            End If
        End If
    Next
    If Not Open_Close = 0 Then Return "Not all existing brackets are Closed"
    Return ""
End Function
Private Function GetTheSameLevel(ByVal s As String) As Integer
    Dim level As Integer = 0
    For i = 0 To s.Length - 1 Step 1
        If s(i).ToString = "," And level = 0 Then
            Return i
        End If
        If s(i).ToString = "(" Then
            level += 1
        End If
        If s(i).ToString = ")" Then
            level -= 1
        End If
    Next
    Return -1
End Function
Private Sub BulidTreeByInTo(ByVal str As String, ByRef l1 As Tree, ByRef r1 As Tree)
    Dim MiddleIndex As Integer = GetTheSameLevel(str)
    Dim p1 As String = str.Substring(0, MiddleIndex)
    Dim p2 As String = str.Substring(MiddleIndex + 1, str.Length - 1 - MiddleIndex)
    Try
        If p1.Contains("(") Then
            If Not p1.Substring(0, p1.IndexOf("(")).ToString = "\" Then
                l1 = New Tree(p1.Substring(0, p1.IndexOf("(")))
                BulidTreeByInTo(p1.Substring(p1.IndexOf("(") + 1, p1.Length - 2 - p1.IndexOf("(")), l1.l, l1.r)
            End If
        Else
            If Not p1 = "\" Then
                l1 = New Tree(p1)
            End If
        End If
        If p2.Contains("(") Then
            If Not p2.Substring(0, p2.IndexOf("(")).ToString = "\" Then
                r1 = New Tree(p2.Substring(0, p2.IndexOf("(")))
                BulidTreeByInTo(p2.Substring(p2.IndexOf("(") + 1, p2.Length - 2 - p2.IndexOf("(")), r1.l, r1.r)
            End If
        Else
            If Not p2 = "\" Then
                r1 = New Tree(p2)
            End If
        End If
    Catch ex As Exception
        Throw ex
    End Try
End Sub
End Class

What you need to do is to generalize your code: at the moment it assumes exactly two children, and your Tree class has fields

Public l As Tree = Nothing
Public r As Tree = Nothing

but you no longer know how many children each tree has, so you need a collection: List is a reasonable choice

Public children As List(Of Tree) = New List(Of Tree)

Note that this is initialized to empty: you'll need to add children to it as you discover it.

Now you need to look at the code that parses the string and finds the children. At the moment you have a function

Private Sub BulidTreeByInTo(ByVal str As String, ByRef l1 As Tree, ByRef r1 As Tree)

This should change to

Private Sub BulidTreeByInTo(ByVal str As String, ByRef ch As List(Of Tree))

Finally you need to modify the implementation of BulidTreeByInTo so that it uses a loop to add as many children as are needed to ch . So, rather than hardcoding the two almost-identical If ... Else ... End If blocks, you need to have just one of those blocks in a loop. I suggest something along the following lines

Do
    Dim MiddleIndex As Integer = GetTheSameLevel(str) ' find comma at same level
    Dim p1 As String = str.Substring(0, MiddleIndex) ' substring up to this comma
    ' str is rest of string past the comma, which can be 0 or more children
    str = str.Substring(MiddleIndex + 1, str.Length - 1 - MiddleIndex)
    Try
        If p1.Contains("(") Then
            If Not p1.Substring(0, p1.IndexOf("(")).ToString = "\" Then
                ch.Add(New Tree(p1.Substring(0, p1.IndexOf("("))))
                BulidTreeByInTo(p1.Substring(p1.IndexOf("(") + 1, p1.Length - 2 - p1.IndexOf("(")), l1.ch)
            End If
        Else
            If Not p1 = "\" Then
                ch.Add(New Tree(p1))
            End If
        End If
    Catch ex As Exception
        Throw ex
    End Try
While MiddleIndex >= 0

It looks to me like your function GetTheSameLevel finds the next comma at the same level and returns <0 if it fails to find the comma, so <0 is the loop termination condition. The idea is that we keep most of your existing code and but rather than having p2 as the right-hand string, we reassign the right-hand string to str . Each time we go through the loop we chop the next bit out of str and assign to p1 .

I'm not a VB programmer and haven't compiled or tested this, but hopefully this gives you enough of an idea of how to proceed?

Following should give you an idea on how to approach:

1(2,3,4(5,3),4(7,8,5))

  1. Take first character, make it the root node. Make its number of children 0. Set current node = root.

  2. Next character shall be a '(', push the last node created on a stack rootHistory. Push the '(' on to a stack newChildren.

  3. Read next character. If it is a numeral, create a new node. Make new node's number of children = 0. Add this to a new vector of nodes called children. You can have a vector of children nodes for each node.

    struct node {
    int value;
    int numOfChildren;
    vector or array of nodes: children[];
    };

  4. If the character read above is a ')', pop out a bracket from the newChildren stack. Pop out the node from the rootHistory, and assign it the vector of children last created.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM