繁体   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