我今天早些时候需要一个可以在单个单元格中显示每个匹配项的 UDF。我记得写了一个可以做到这一点的函数,我回到这里是为了重用我的代码。
对我来说不幸的是,它是针对 OPs 问题的,对于我当前的需求不够灵活。
我的损失就是你的收获!
所以现在,我已经完全重写了函数以接受Range.Find 中的几乎所有参数。据我所知,工作表中没有像 xlByColums 这样的 Excel 枚举器。我不可能很快记住所有这些,所以我通过将大多数参数转换为布尔值使事情变得更容易。 searchByColumn、findPartialMatch、reverseSearchDirection、caseSensitive 和 lookAtFormat 均通过 True/False 设置,但 xlFindLookIn 仍需要常量值来指定 cmets/formulas/values。
这还不是全部……
输出不必是匹配项。它可以是匹配项的地址或偏移量。想象一下,如果VLOOKUP 或INDEXMATCH 将它们匹配的所有内容放入一个单元格中,这基本上就是偏移参数所允许的。在重要的时候,输出可以包括匹配的总数。
但是等等,还有更多!
一个小但非常重要的选项,分隔符可以通过参数从工作表中设置。
我只想说,这个函数可以有多种使用方式,我不可避免地会在某个时候回来重用它。
请注意,我使用了具有两个不同条件退出点的无限循环,逻辑应该清晰易懂,但如果您开始编辑代码,则需要注意这一点。
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