簡體   English   中英

Excel VBA-使用FindNext后功能停止(在子例程中工作)

[英]Excel VBA - Function Stops after using FindNext (Works in Subroutine)

我正在編寫一個函數,該函數將在名為“ Usage”的指定工作表的列中找到所有單元格,該工作表將具有多個與我所找到的內容匹配的單元格。 問題是,當我嘗試調用FindNext時,VBA停止工作而不會引發任何錯誤。 但是,如果我將函數更改為子例程,則它可以很好地工作,因為“調試”將顯示找到的所有10個單元地址 但是我需要使用一個函數,因為我將根據找到的結果返回一個值。 當我逐步使用F8時,在調試行上使用FindNext之后,我的函數立即停止-至少有10個值與要傳遞的項匹配。關於為什么它作為子例程而不是函數的原因完全感到困惑。

Function FindAllCells(item As String) As String

  Dim searchRange As Range
  Dim foundItem As Range
  Dim firstCellAddress As String

  Set searchRange = Sheets("Usage").Range("A:A")
  Set foundItem = searchRange.Find(What:=item, LookAt:=xlWhole)

  If foundItem Is Nothing Then
    Exit Function
  End If

  firstCellAddress = foundItem.Address

  Do 
    Set foundItem = searchRange.FindNext(foundItem)
    Debug.Print foundItem.Address
  Loop While firstCellAddress <> foundItem.Address

  FindAllCells = foundItem.Offset(0,2)
End Function  

問題是.FindNext在UDF中不起作用 (從Excel公式調用)。

您可以通過使用另一個.Find來解決此問題。

其他幾點:

  1. 我也會通過搜索范圍,使其更加靈活
  2. 如果未指定,某些Find參數(取自VBA或用戶)使用上一次使用Find值。 看這里
Function FindAllCells(searchRange As Range, item As String) As String
    Dim foundItem As Range
    Dim firstCellAddress As String

    Set foundItem = searchRange.Find(What:=item, After:=searchRange.Cells(searchRange.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows)
    If foundItem Is Nothing Then Exit Function

    firstCellAddress = foundItem.Address
    Do
        Set foundItem = searchRange.Find(What:=item, After:=foundItem, LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows)
        Debug.Print foundItem.Address
    Loop While firstCellAddress <> foundItem.Address

    FindAllCells = foundItem.Offset(0, 2)
End Function

叫像

=FindAllCells(Usage!$A:$A,"item")

也就是說,鑒於您對自己更大目標的一些評論,我認為您的世界充滿了傷害

我今天早些時候需要一個UDF,它可以在一個單元格中顯示所有匹配項。 我記得寫了一個可以做到這一點的函數,而我回到這里的目的是重用我的代碼。

對我來說不幸的是,它是針對OP的問題,不夠靈活,無法滿足我當前的需求。

我的損失是您的收益!

所以現在,我已經完全重寫了該函數以接受Range.Find幾乎每個參數。 據我所知,工作表中沒有xlByColums類的Excel枚舉器。 我不可能很快記住所有這些,所以我通過將大多數參數轉換為布爾值使事情變得更容易。 searchByColumnfindPartialMatchreverseSearchDirectioncaseSensitivelookAtFormat都通過True / False進行設置,但是xlFindLookIn仍需要常量值來指定注釋/公式/值。

這還不是全部...

輸出不必是匹配項。 它可以是匹配項的地址或偏移量。 想象一下,如果VLOOKUPINDEXMATCH將它們匹配的所有內容放到單個單元格中,那基本上就是offset參數所允許的。 對於那些重要的時間,輸出可以包括匹配的總數。

但是,等等,還有更多!

一個很小但意義重大的選項,可以通過參數在工作表中設置定界符。

可以說,此函數可以以多種方式使用,我不可避免地會在某個時候回來重用它。

請注意,我使用了帶有兩個不同條件退出點的無限循環,其邏輯應該清晰易懂,但是如果您開始編輯代碼,則需要提防這一問題。

Public Function FindAllMatches(ByVal searchFor As String, ByVal searchRange As Range, _
                                    Optional ByVal columnOffset As Long, _
                                    Optional ByVal rowOffset As Long, _
                                    Optional ByVal countMatches As Boolean, _
                                    Optional ByVal showAddresses As Boolean, _
                                    Optional ByVal delimiter As String, _
                                    Optional ByVal findPartialMatch As Boolean = True, _
                                    Optional ByVal searchByColumn As Boolean = False, _
                                    Optional ByVal reverseDirection As Boolean = False, _
                                    Optional ByVal caseSensitive As Boolean = False, _
                                    Optional ByVal lookAtFormat As Boolean = False, _
                                    Optional ByVal lookInside As XlFindLookIn = xlValues _
                                    ) As String

    Dim firstMatchCellAddress As String
    Dim searchResult As Range
    Dim returnString As String
    Dim matchCount As Long
    Dim includePartial As Single: includePartial = -findPartialMatch + 1
    Dim previousDirection As Single: previousDirection = -reverseDirection + 1
    Dim searchAxis As Single: searchAxis = -searchByColumn + 1

    If Not CBool(Len(delimiter)) Then delimiter = Chr(44)
    Set searchResult = searchRange

    Do
        Set searchResult = searchRange.Find(What:=searchFor, After:=searchResult.Cells(searchResult.Cells.Count), LookIn:=lookInside, _
                LookAt:=includePartial, SearchOrder:=searchAxis, SearchDirection:=previousDirection, _
                MatchCase:=caseSensitive, SearchFormat:=lookAtFormat)

        Select Case True

            Case searchResult Is Nothing
                Exit Do

            Case firstMatchCellAddress = searchResult.Address
                Exit Do

            Case CBool(Len(returnString))
                If showAddresses Then
                    returnString = returnString & delimiter & searchResult.Offset(rowOffset, columnOffset).Address
                Else
                    returnString = returnString & delimiter & searchResult.Offset(rowOffset, columnOffset)
                End If

            Case Else
                If showAddresses Then
                    returnString = searchResult.Offset(rowOffset, columnOffset).Address
                Else
                    returnString = searchResult.Offset(rowOffset, columnOffset)
                End If

                firstMatchCellAddress = searchResult.Address

        End Select

        matchCount = matchCount + 1

    Loop While True

    If countMatches Then
        If CBool(matchCount) Then
            returnString = matchCount & delimiter & returnString
        Else
            returnString = 0
        End If
    End If

    FindAllMatches = returnString

End Function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM