使用Excel VBA查找工作簿中的所有匹配项

MZi*_*an6 13 excel vba excel-vba

我正在尝试编写一个VBA将采用字符串的例程,搜索给定的Excel工作簿,并将所有可能的匹配返回给我.

我目前有一个可行的实现,但它非常慢,因为它是一个双循环.当然,内置的Excel Find函数被"优化"以找到单个匹配,但我希望它返回一个初始匹配数组,然后我可以应用其他方法.

我将发布一些已经存在的伪代码

For all sheets in workbook
    For all used rows in worksheet
        If cell matches search string
            do some stuff
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

如前所述,这个双循环使得运行速度非常慢,所以我希望尽可能摆脱这种情况.有什么建议?

UPDATE

虽然下面的答案会改进我的方法,但我最终会遇到一些稍微不同的东西,因为我需要反复做多个查询.

我决定循环遍历文档中的所有行,并创建一个包含每个唯一行的键的字典.然后,它指向的值将是可能匹配的列表,因此当我稍后查询时,我只需检查它是否存在,如果是,则只需获取匹配的快速列表.

基本上只是在做一个初步横扫一切都存储在一个可管理的结构,然后查询该结构可以在完成O(1)时间

Jer*_*ino 23

如上所述,使用Range.Find方法以及工作簿中每个工作表的循环是最快的方法.例如,下面的字符串"Question?" 在每个工作表中,并用字符串"已回答!"替换它.

Sub FindAndExecute()

Dim Sh As Worksheet
Dim Loc As Range

For Each Sh In ThisWorkbook.Worksheets
    With Sh.UsedRange
        Set Loc = .Cells.Find(What:="Question?")
        If Not Loc Is Nothing Then
            Do Until Loc Is Nothing
                Loc.Value = "Answered!"
                Set Loc = .FindNext(Loc)
            Loop
        End If
    End With
    Set Loc = Nothing
Next

End Sub
Run Code Online (Sandbox Code Playgroud)

  • 对于稍后出现的任何人,此代码避免了无限循环,因为该值被更改为搜索查询以外的其他内容.没有它,它将继续无休止地搜索. (6认同)

cyb*_*onk 21

基于 Ahmed 的回答,经过一些清理和概括,包括其他“查找”参数,因此我们可以在任何情况下使用此函数:

'Uses Range.Find to get a range of all find results within a worksheet
' Same as Find All from search dialog box
'
Function FindAll(rng As Range, What As Variant, Optional LookIn As XlFindLookIn = xlValues, Optional LookAt As XlLookAt = xlWhole, Optional SearchOrder As XlSearchOrder = xlByColumns, Optional SearchDirection As XlSearchDirection = xlNext, Optional MatchCase As Boolean = False, Optional MatchByte As Boolean = False, Optional SearchFormat As Boolean = False) As Range
    Dim SearchResult As Range
    Dim firstMatch As String
    With rng
        Set SearchResult = .Find(What, , LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat)
        If Not SearchResult Is Nothing Then
            firstMatch = SearchResult.Address
            Do
                If FindAll Is Nothing Then
                    Set FindAll = SearchResult
                Else
                    Set FindAll = Union(FindAll, SearchResult)
                End If
                Set SearchResult = .FindNext(SearchResult)
            Loop While Not SearchResult Is Nothing And SearchResult.Address <> firstMatch
        End If
    End With
End Function
Run Code Online (Sandbox Code Playgroud)

  • 这应该是最终的解决方案,比公认的解决方案更有用、更通用! (4认同)