22

VBA文字列を取得し、特定の Excel ワークブックを検索して、考えられるすべての一致を返すルーチンを作成しようとしています。

現在、機能する実装がありますが、二重の for ループであるため、非常に低速です。もちろん、組み込みの ExcelFind関数は単一の一致を見つけるように「最適化」されていますが、最初の一致の配列を返し、さらにメソッドを適用できるようにしたいと考えています。

私はすでに持っているもののいくつかの擬似コードを投稿します

For all sheets in workbook
    For all used rows in worksheet
        If cell matches search string
            do some stuff
        end
    end
end

前に述べたように、この二重の for ループは実行を非常に遅くするため、可能であればこれを取り除くことを検討しています。助言がありますか?

アップデート

以下の回答で私の方法は改善されましたが、複数のクエリを何度も実行する必要があったため、最終的にはわずかに異なるものになりました。

代わりに、ドキュメント内のすべての行をループして、一意の行ごとにキーを含む辞書を作成することにしました。これが指す値は、可能な一致のリストになるため、後でクエリを実行するときに、存在するかどうかを確認し、存在する場合は、一致の簡単なリストを取得できます。

基本的には、最初のスイープを 1 回実行してすべてを管理可能な構造に格納し、その構造をO(1)時間内にクエリするだけです。

4

7 に答える 7

31

上で指摘したように、ワークブック内の各ワークシートのループと共に Range.Find メソッドを使用するのが、これを行うための最速の方法です。たとえば、次の例では、文字列「Question?」を見つけます。各ワークシートで、"Answered!" という文字列に置き換えます。

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
于 2013-10-22T04:37:37.597 に答える
24

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

使用法はネイティブ .Find と同じですが、要求された使用例を次に示します。

Sub test()
  Dim SearchRange As Range, SearchResults As Range, rng As Range
    Set SearchRange = MyWorksheet.UsedRange
    Set SearchResults = FindAll(SearchRange, "Search this")
    
    If SearchResults Is Nothing Then
        'No match found
    Else
        For Each rng In SearchResults
            'Loop for each match
        Next
    End If
End Sub
于 2019-03-26T02:40:17.787 に答える
-1

データを配列に読み取ることができます。そこから、一度に 1 つのセルを読み取る代わりに、メモリ内で照合を行うことができます。

セルの内容を VBA 配列に渡す

于 2013-10-21T21:20:37.550 に答える