0

我有一个 VB.NET 应用程序,用于将各种文件加载到 RichTextBox 中,然后扫描文档以查找特定单词。它类似于 Word 中的查找功能。该应用程序运行良好,直到运行了 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
4

4 回答 4

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
于 2013-09-30T19:39:48.030 回答
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条线是不必要的。您已经在遍历一个列表,因此您无需在进行过程中删除这些项目。就目前而言,您的循环将跳过列表中的所有其他项目。

于 2013-09-30T19:39:17.927 回答
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
于 2013-09-30T20:19:45.443 回答
1

哎呀。我错过了关于 IndexOf 的一个非常重要的观点(并且错误地认为它是在最后一场比赛结束时提供的)。请参阅马格努斯的回答。


我不确定瓶颈在哪里(很可能来自设置选择本身),但这里是我的建议,大致按优先顺序排列:

  1. 调用 rtbFile.Text 一次以避免到底层控件(可能是本机 Windows 控件?)的任何往返,并使用变量来存储结果字符串。在 .NET 中获取字符串后,请继续直接使用它,除非/直到文本可能更改。如果控件是本机的,那么可能需要做很多工作才能简单地“获取文本”。

  2. 在计数集合上使用正常的项目迭代(不是索引),并且在分配选择时不要从列表的前面删除。从列表的前面删除是“昂贵的”,因为它必须在内部将所有项目向下移动。此外,这里不需要删除元素并且充其量是可疑的:因为正在修改的集合也在被迭代,这可能导致不正确的行为(跳过的项目),无论性能如何。

  3. 每个循环只调用一次 IndexOf并使用变量来避免重复搜索。这可能不会产生整体影响,但它确实避免了一些“额外”的工作。IndexOf 本身很好,不需要更换。

YMMV。

于 2013-09-30T19:35:11.310 回答