我有一个VB.NET应用程序,我用它将各种文件加载到RichTextBox中,然后扫描文档以查找特定的单词。它类似于Word中的Find功能。该应用程序运行良好,直到一个5,150行.sql文件运行它,它需要超过10分钟才能运行完成。
有人可以推荐一种比下面更好的编码方式吗?
If sqlText.Contains("GRANT") Then
Dim searchstring As String = "GRANT"
Dim count As New List(Of Integer)()
For i As Integer = 0 To rtbFile.Text.Length - 1
If rtbFile.Text.IndexOf(searchstring, i) <> -1 Then
count.Add(rtbFile.Text.IndexOf(searchstring, i))
End If
Next
Try
For i As Integer = 0 To count.Count - 1
rtbFile.Select(count(i), searchstring.Length)
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
count.RemoveAt(i)
Next
Catch ex As Exception
End Try
rtbFile.Select(rtbFile.Text.Length, 0)
rtbFile.SelectionBackColor = Color.White
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Regular)
End If
答案 0 :(得分:3)
第一个循环正在杀死性能,你为字符串中的每个字符调用IndexOf
。两个循环也可以合并为一个。将其更改为:
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
For Each m As Match in Regex.Matches(sertbFile.Text, searchstring)
rtbFile.Select(m.Index, searchstring.Length)
Next
答案 1 :(得分:2)
你在这里发生了一些不好的事情:
首先,以下代码:
For i As Integer = 0 To rtbFile.Text.Length - 1
If rtbFile.Text.IndexOf(searchstring, i) <> -1 Then
count.Add(rtbFile.Text.IndexOf(searchstring, i))
End If
Next
这循环遍历字符串中的每个字符,并从该点向前调用整个字符串上的IndexOf
。所以你的50,000个字符的字符串在大字符串上运行IndexOf
50,000次。
您只需要在找到字符串时多次调用IndexOf
。找到字符串后,将起始索引增加到该点,并继续仅从该点开始搜索。
接下来,这段代码:
For i As Integer = 0 To count.Count - 1
...
count.RemoveAt(i)
Next
RemoveAt
行是不必要的。您已经在列表中循环,因此您不需要在移动时删除这些项目。它的方式,你的循环将跳过列表中的每个其他项目。
答案 2 :(得分:2)
这也可以使用While循环和RichTextBox.Find():
来完成 Dim searchstring As String = "GRANT"
Dim index As Integer = rtbFile.Find(searchstring, 0, RichTextBoxFinds.None)
While index <> -1
rtbFile.Select(index, searchstring.Length)
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
index = rtbFile.Find(searchstring, index + searchstring.Length, RichTextBoxFinds.None)
End While
答案 3 :(得分:1)
糟糕。我错过了关于IndexOf的一个非常重要的观点(错误地认为它是在最后一场比赛结束时进行的)。见马格努斯的答案。
我不确定瓶颈在哪里(而且很可能是设置选择本身),但这是我的建议,大致按优先顺序排列:
调用rtbFile.Text一次以避免任何往返底层控件的往返(可能是本机Windows控件?)并使用变量来存储生成的字符串。一旦在.NET中获得字符串,只需继续使用它,除非/直到文本可能更改。如果控件是原生的,那么可能需要很多工作来简单地“获取文本”。
对计数集合(不是索引)使用正常项目迭代,并且在分配选择时不要从列表的前面删除。从List的前面删除是“昂贵的”,因为它必须在内部向下移动所有项目。此外,删除元素在这里是不必要的,并且充其量是可疑的:因为被修改的集合也正在被迭代,这可能导致不正确的行为(跳过的项目),而不管性能如何。
< / LI>每个循环只调用一次IndexOf 并使用变量来避免重复搜索。这可能不会产生整体影响,但它确实避免了一些“额外”的工作。 IndexOf本身很好,不需要更换。
因人而异。