使用ArrayList将文本文件拆分并存储到数组中

时间:2014-09-23 13:33:07

标签: arrays vb.net arraylist

我一直在开发一个使用文本文件来存储问题的测验应用程序。

问题的格式为"QUESTION##CHOICE_A##CHOICE_B##CHOICE_C##CHOICE_D##ANSWER" 我想让它读取每一行,使用"##"作为拆分字符串将其拆分为6个不同的部分,并将其存储到数组中,例如Questions, CHOICE_A,CHOICE_B,CHOICE_C,CHOICE_D

我的代码没有循环。它只存储第一行

问题的下方显示了图形说明

enter image description here enter image description here

这是我的代码

Dim sr As StringReader = New StringReader(My.Resources.ResourceManager.GetObject(globalVariables.currSubject))

    Dim questions As String

    Dim splitquestions(6) As String

    Dim Unsplitquestions(6) As String




    Dim i As Integer = 0

    Do Until sr.Peek = -1

        questions = sr.ReadLine

        Unsplitquestions(i) = questions

        splitquestions = Unsplitquestions(i).Split(New String() {"##"}, StringSplitOptions.RemoveEmptyEntries)

        ' Splits and Stores Into Various 
        '
        '


        globalVariables.ArrayQuestions.Add(splitquestions(0))

        globalVariables.optionA.Add(splitquestions(1))

        globalVariables.optionB.Add(splitquestions(2))

        globalVariables.optionC.Add(splitquestions(3))

        globalVariables.optionD.Add(splitquestions(4))

        globalVariables.Answer.Add(splitquestions(5))

    Loop

2 个答案:

答案 0 :(得分:3)

不,不要使用ArrayList来操作这样的一组对象。您应该尝试以面向对象的方式思考。 QuestionEntry是一个包含QuestionText,4个可能的问题答案和一个QuestionAnswer的实体。

让我们试试这段代码

Public Class QuestionEntry
   Public QuestionText as String
   Public ChoiceA as String
   Public ChoiceB as String
   Public ChoiceC as String
   Public ChoiceD as String
   Public QuestionAnswer as String
End Class

Dim questions = new List(Of QuestionEntry)()
Dim line As String
Do While sr.Peek() >= 0
    line = sr.ReadLine
    Console.WriteLine(line)
    Dim parts = line.Split(New String() {"##"}, StringSplitOptions.RemoveEmptyEntries)
    Dim q = new QuestionEntry()
    With q

            .QuestionText = parts(0)
            .ChoiceA = parts(1)
            .ChoiceB = parts(2)
            .ChoiceC = parts(3)
            .ChoiceD = parts(4)
            .QuestionAnswer = parts(5)

    End With
    questions.Add(q)
Loop

当然这只是一个例子,需要进行一些错误检查才能使代码更安全。例如,在创建新的问题条目之前,您应该检查分割返回的数组是否有效地包含6个元素。 (parts.Length = 6)

现在你的所有文本都由List(Of QuestionEntry)的实例处理,你可以像普通数组一样使用它

Dim qe = questions(0)
Console.WriteLine("Question: " & qe.QuestionText)
Console.WriteLine("Choice A: " & qe.ChoiceA)
Console.WriteLine("Choice B: " & qe.ChoiceB)
Console.WriteLine("Choice C: " & qe.ChoiceC)
Console.WriteLine("Choice D: " & qe.ChoiceD)
Console.ReadLine("Enter your answer:")

答案 1 :(得分:1)

执行此操作的最佳方法是依赖现有的分隔数据解析器。 .Split()方法通常非常糟糕:性能低于标准,并且所有边缘情况的国王(比你想象的还要多)它在哪些方面运作良好。甚至还有一个解析器已经内置到.Net:Microsoft.VisualBasic.FileIO.TextFieldParser中。

此外,ArrayLists实际上只存在pre-.Net 2.0兼容性。没有任何理由再次使用它了。至少,使用通用List(Of String)。但是,在这种情况下,您的最佳选项是构建快速类:

Public Class Question
    Public Property QuestionText As String
    Public Property OptionA As String
    Public Property OptionB As String
    Public Property OptionC As String
    Public Property OptionD As String
    Public Property Answer As String
End Class

现在你读到这样的文件:

Dim results As New List(Of Question)()
Using rdr As New TextFieldParser(My.Resources.ResourceManager.GetObject(globalVariables.currSubject))
    rdr.Delimiters = new String() {"##"}
    Dim row() As String

    While Not rdr.EndOfData
        row = rdr.ReadFields()
        results.Add(New Question() {
             QuestionText = row(0), 
             OptionA = row(1), 
             OptionB = row(2), 
             OptionC = row(3),
             OptionD = row(4), 
             Answer = row(5)
         })
    End While
End Using

即使使用了课程定义,整个代码也比原始代码少,而且维护起来也更容易。

我也很想把它写成Iterator

Public Iterator Function ReadQuestions(ByVal FileName As String) As IEnumerable(Of Question)
    Using rdr As New TextFieldParser(FileName)
        rdr.Delimiters = new String() {"##"}
        Dim row() As String

        While Not rdr.EndOfData
            row = rdr.ReadFields()

            Yield New Question() {
                QuestionText = row(0), 
                OptionA = row(1), 
                OptionB = row(2), 
                OptionC = row(3),
                OptionD = row(4), 
                Answer = row(5)
            }
        End While
    End Using
End Function

我有两个最后的修改建议。第一个将构造函数添加到接受字符串数组的Question类型。这将从代码中删除一点高级语法(对象初始化程序),并简化对实际读取数据的代码部分的读取。第二种方法是使ReadQuestions()方法成为Question类型的共享成员。最终结果如下:

Public Class Question
    Public Property QuestionText As String
    Public Property OptionA As String
    Public Property OptionB As String
    Public Property OptionC As String
    Public Property OptionD As String
    Public Property Answer As String

    Public Sub New(ByVal data() As String)
        'Add error handling here
        QuestionText = data(0), 
        OptionA = data(1), 
        OptionB = data(2), 
        OptionC = data(3),
        OptionD = data(4), 
        Answer = data(5)
    End Sub

    Public Shared Iterator Function ReadFromFile(ByVal FileName As String) As IEnumerable(Of Question)
        Using rdr As New TextFieldParser(FileName)
            rdr.Delimiters = new String() {"##"}

            While Not rdr.EndOfData                                
                Yield New Question(rdr.ReadFields()) 
            End While
        End Using
    End Function
End Class

你可以从你现有的代码中调用所有这些:

Dim Questions = Question.ReadFromFile(My.Resources.ResourceManager.GetObject(globalVariables.currSubject))
For Each q As Question in Questions
    '...
Next