リスト文字列を1文字ずつパース 再帰じゃないよ編

再帰によるパースは大きいテキストでこけるので再帰しないバージョン。

Imports System
Imports System.Collections.Generic

' Ruby の Fixnum っぽいクラス
Public Class Fixnum
    Private num_ As Integer

    Public Sub New(ByVal n As Integer)
        Me.num_ = n
    End Sub

    Public Property Value() As String
        Get
            Return Me.num_
        End Get
        Set(ByVal val As String)
            Me.num_ = val
        End Set
    End Property

    Public Function Inc()
        Me.num_ += 1
        Return Me.num_
    End Function

    Public Function Dec()
        Me.num_ -= 1
        Return Me.num_
    End Function

    Public Function isZero()
        Return Me.num_ = 0
    End Function

    Public Function isNonZero()
        Return Not isZero()
    End Function

End Class

Public Class ListObject
    Private Lstr As New List(Of Object)

    Sub New()
        Me.Lstr = New List(Of Object)
        Lstr.Add(Nothing)
    End Sub

    Public Function Head()
        Return Lstr(0)
    End Function

    Public Function Last()
        Return Lstr(Lstr.Count - 2)
    End Function

    Public Function Last2()
        Return Lstr(Lstr.Count)
    End Function

    Public Sub Clear()
        Lstr.Clear()
        Lstr.Add(Nothing)
    End Sub

    Public Function Tail()
        Dim Tarray() As Object = New Object(Lstr.Count) {}
        Dim i As Object
        Dim TailList As New ListObject

        Lstr.CopyTo(1, Tarray, 0, Lstr.Count - 1)
        TailList.Clear()
        For Each i In Tarray
            TailList.Push(i)
        Next i

        Return TailList
    End Function

    Public Sub Push(ByRef value As Object)
        Lstr(Lstr.Count - 1) = value
        Lstr.Add(Nothing)
    End Sub

    Public Sub Pop()
        If Lstr.Count > 1 Then
            Lstr.Remove(Nothing)
            Lstr(Lstr.Count - 1) = Nothing
        End If
    End Sub

    Public Function Show()
        Return "{" + AllList(Me) + "}"
    End Function

    Private Function AllList(ByRef list As ListObject)
        If IsNothing(list.Head) Then
            Return ""
        Else
            Return Tostr(list.Head()) + sPace(list.Tail) + AllList(list.Tail)
        End If
    End Function

    Private Function IsNothing(ByRef cell As Object)
        If TypeOf cell Is ListObject Then
            Return False
        Else
            If cell = Nothing Then
                Return True
            Else
                Return False
            End If
        End If
    End Function

    Private Function Tostr(ByRef cell As Object)
        If TypeOf cell Is ListObject Then
            Return cell.Show
        Else
            If TypeOf cell Is String Then
                Return """" + cell + """"
            Else
                Return cell.ToString
            End If
        End If
    End Function

    Private Function sPace(ByRef list As ListObject)
        If IsNothing(list.Head) Then
            Return ""
        Else
            Return ","
        End If
    End Function
End Class

Module Module1

    Function StringToList(ByVal inString As String)
        Dim out As New ListObject
        Dim Str As String = ""
        Dim flag As Boolean = False
        Dim CharArray As Char() = New Char(inString.Length) {}
        Dim cnt As Fixnum = New Fixnum(inString.Length)
        Dim ch As Char

        inString.CopyTo(0, CharArray, 0, inString.Length)

        For Each ch In CharArray
            cnt.Dec()
            System.Console.Write("ch:" & ch & " ")
            If cnt.isZero Then
                System.Console.WriteLine(out.Show)
                Return out.Head
            Else
                ' "[" のときは末尾に空のリストを追加
                If ch = "[" Then
                    Dim ls As New ListObject
                    out.Push(ls)
                    System.Console.WriteLine(out.Show)
                    Continue For
                ' "]" のときは末尾の要素を一段ネストの低いリストに追加
                ElseIf ch = "]" Then
                    Dim last As ListObject = out.Last
                    out.Pop()
                    Dim last2 As ListObject = out.Last
                    out.Pop()
                    last2.Push(last)
                    out.Push(last2)
                    System.Console.WriteLine(out.Show)
                    Continue For
                ' "," は何もしない
                ElseIf ch = "," Then
                    System.Console.WriteLine(out.Show)
                    Continue For
                ' スペースは文字列フラグが立っているときだけ文字列に追加
                ElseIf ch = " " Then
                    If flag Then
                        Str += ch
                    End If
                    System.Console.WriteLine(out.Show)
                    Continue For
                ' """" は文字列フラグが立っているときは文字列の終了
                ' 末尾のリストに文字列を追加。文字列のワークエリアをクリア
                ElseIf ch = """" Then
                    If flag Then
                        Dim ls As New ListObject
                        ls = out.Last
                        ls.Push(Str)
                        out.Pop()
                        out.Push(ls)
                        Str = ""
                        flag = False
                        System.Console.WriteLine(out.Show)
                        Continue For
                    Else
                    ' 文字列フラグが立っていないので文字列の開始
                        flag = True
                        System.Console.WriteLine(out.Show)
                        Continue For
                    End If
                Else
                    ' 文字列に1文字追加
                    Str += ch
                    System.Console.WriteLine(out.Show)
                    Continue For
                End If
            End If
        Next ch
        Return out.Head
    End Function


    Sub Main()
        Dim Lstr As String = "[[""A"",[""B""]],[[[""C""],""D""],""1""]]"
        Dim r As New ListObject
        r = StringToList(Lstr)
        Console.WriteLine("in  :" & Lstr)                 ' in  :[["A",["B"]],[[["C"],"D"],"1"]]
        System.Console.WriteLine("out :" & r.Show)        ' out :{{"A",{"B"}},{{{"C"},"D"},"1"}}
        System.Console.WriteLine("Head:" & r.Head.Show)   ' Head:{"A",{"B"}}
        System.Console.WriteLine("Tail:" & r.Tail.Show)   ' Tail:{{{{"C"},"D"},"1"}}
    End Sub
End Module

パースする様子。

ch:[ {{}}
ch:[ {{},{}}
ch:" {{},{}}
ch:A {{},{}}
ch:" {{},{"A"}}
ch:, {{},{"A"}}
ch:[ {{},{"A"},{}}
ch:" {{},{"A"},{}}
ch:B {{},{"A"},{}}
ch:" {{},{"A"},{"B"}}
ch:] {{},{"A",{"B"}}}
ch:] {{{"A",{"B"}}}}
ch:, {{{"A",{"B"}}}}
ch:[ {{{"A",{"B"}}},{}}
ch:[ {{{"A",{"B"}}},{},{}}
ch:[ {{{"A",{"B"}}},{},{},{}}
ch:" {{{"A",{"B"}}},{},{},{}}
ch:C {{{"A",{"B"}}},{},{},{}}
ch:" {{{"A",{"B"}}},{},{},{"C"}}
ch:] {{{"A",{"B"}}},{},{{"C"}}}
ch:, {{{"A",{"B"}}},{},{{"C"}}}
ch:" {{{"A",{"B"}}},{},{{"C"}}}
ch:D {{{"A",{"B"}}},{},{{"C"}}}
ch:" {{{"A",{"B"}}},{},{{"C"},"D"}}
ch:] {{{"A",{"B"}}},{{{"C"},"D"}}}
ch:, {{{"A",{"B"}}},{{{"C"},"D"}}}
ch:" {{{"A",{"B"}}},{{{"C"},"D"}}}
ch:1 {{{"A",{"B"}}},{{{"C"},"D"}}}
ch:" {{{"A",{"B"}}},{{{"C"},"D"},"1"}}
ch:] {{{"A",{"B"}},{{{"C"},"D"},"1"}}}
ch:] {{{"A",{"B"}},{{{"C"},"D"},"1"}}}

今のところリストの中味は全部文字列。