我一直在开发一个使用文本文件来存储问题的测验应用程序。
问题的格式为"QUESTION##CHOICE_A##CHOICE_B##CHOICE_C##CHOICE_D##ANSWER"
我想让它读取每一行,使用"##"
作为拆分字符串将其拆分为6个不同的部分,并将其存储到数组中,例如Questions, CHOICE_A,CHOICE_B,CHOICE_C,CHOICE_D
我的代码没有循环。它只存储第一行
问题的下方显示了图形说明
这是我的代码
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
答案 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