查找和FindNext for Excel VBA

时间:2015-05-21 17:25:06

标签: excel vba excel-vba

我一直在试图弄清楚如何处理这个问题,但基本上我想要一种方法来打印出B列中的值,给定一个与A列匹配的特定值。例如:

Column A    Column B
1           ABC
2           DEF
3           GHI
1           JKL

我想在使用find / findnext或其他任何东西后打印出这个字符串:

ABC JKL

我尝试使用

Set cellFound = ActiveWorkbook.Worksheets("sheet1").Range("F1:F1000000").Find("1")
string = cellFound.Offset(0, 1).value

我有一个循环遍历所需的所有行所需的时间。但是使用find它会让我返回相同的第一个字符串(" ABC")并且该字符串最终是ABC ABC而不是ABC JKL

我尝试使用FindNext而不是find,但我得到的是1004错误。所以我不确定我做错了什么。任何人都有任何想法?

5 个答案:

答案 0 :(得分:4)

如果你在前一个查找之后启动,则不需要 FindNext

Sub qwerty()
   Dim rFirst As Range, r As Range
   Dim A As Range
   Set A = Range("A:A")
   Do
      If rFirst Is Nothing Then
         Set rFirst = A.Find(What:=1, After:=A(1))
         Set r = rFirst
      Else
         Set r = A.Find(What:=1, After:=r)
         If r.Address = rFirst.Address Then Exit Do
      End If
         MyString = MyString & " " & r.Offset(0, 1)
   Loop

   MsgBox MyString
End Sub

enter image description here

答案 1 :(得分:4)

您需要拨打Find一次,然后再联系FindNext

Dim rng As Excel.Range
Set rng = ActiveWorkbook.Worksheets("sheet1").Range("F1:F1000000")
Set cellFound = rng.Find("1")
Do While Not cellFound Is Nothing
    Set cellFound = rng.FindNext
Loop

参考:

答案 2 :(得分:1)

使用Range.FindNext方法时,只需包含一些对初始查找位置的引用。例如,我使用excel记录了这个宏。虽然我不喜欢使用选择和激活,但我认为这有助于了解该方法的功能:

Sub Using_Find()
    Selection.Find(What:="my search string here", After:=ActiveCell _
        , LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, _
        SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False).Activate
    Selection.FindNext(After:=ActiveCell).Activate
    Selection.FindNext(After:=ActiveCell).Activate
    Selection.FindNext(After:=ActiveCell).Activate
    Selection.FindNext(After:=ActiveCell).Activate
    Selection.FindNext(After:=ActiveCell).Activate
    Selection.FindNext(After:=ActiveCell).Activate
End Sub

要生成此子例程,我在excel中使用了record>宏,然后选择Home> Find&Select> Find。

我看到此子例程工作的方式是:

步骤1:找到字符串的第一个位置,将其激活;

步骤2:FindNext在我们刚刚激活的活动单元格之后的之后,找到该字符串的下一个位置,然后将其激活;

等等因此,这里的观察结果是.FindNext方法需要对先前的查找单元格进行一些引用(第一个答案是通过手动将其标识为唯一引用来完成的)。我没有对这个答案说什么,它也一样有效。我的目标是帮助您深入了解Range.FindNext方法。

其他一些值得一提的地方:

Range.FindNext将返回一个 Range 对象。 (微软)

之后参数描述为:

“要搜索的单元格。它对应于从用户界面进行搜索时活动单元格的位置。请注意,After必须是该范围内的单个单元格。请记住,搜索开始在此单元格之后;直到方法返回到该单元格之前,不搜索指定的单元格。如果未指定此参数,则在范围左上角的单元格之后开始搜索。” (微软)

...和

备注部分下,Microsoft指出:“搜索将绕到范围的开头。”他们建议保存第一个地址,并对每个后续的.FindNext进行检查。这样一来,方法一旦完成环绕操作,就会首先检查地址,然后结束检查。

因此,对Microsoft提供的Range.FindNext方法进行建模,我编写了此介绍性子例程进行审查:

Sub USING_FIND()
'this line sets the range to our used range on the active sheet
    With ActiveSheet.UsedRange
'setting c variable to .Find method, where the first value is what we're looking for,
'i.e. "1"; LookIn:= can be changed to our needs but set currently to xlValues
        Set c = .Find(1, LookIn:=xlValues)
'begin first conditional; this conditional checks c (our .Find method) to see if it has
'some reference, then sets the address to a constant 'firstAddress' so we can check it
'against the .FindNext returns later to prevent endless loop
        If Not c Is Nothing Then
            firstAddress = c.Address
'Do...is where we place our "work"; this can be a redirect to another function/sub, etc
'for now I've just tossed a msgbox as a placeholder that returns the offset 1 column over
            Do
                MsgBox c.Offset(0, 1)
'Now we set c to the .FindNext method, using the original .Find method as the 'after'
        Set c = .FindNext(c)
'Another empty reference check/exit as a conditional
    If c Is Nothing Then
        GoTo DoneFinding
'ends the empty reference conditional
    End If
'using our .FindNext method that we replaced 'c' with earlier, we can now loop through
'the remainder of the value returns.  The Loop While 'c.Address <> firstAddress' sentence
'is checking that each subsequent .FindNext address IS NOT the first address;
'-our loop will return to the 'Do' sentence to repeat the loop, starting on the
'MsgBox c.Offset(0,1) sentence with the next string occurence
'-the characters '<>' means 'does not equal'; i.e. the opposite of '='
    Loop While c.Address <> firstAddress
'this ends the address check loop
    End If
DoneFinding:
    End With
End Sub

要根据您的特定需求调整此代码,我们可以在 Do 行的 之后更改句子:'MsgBox c.Offset(0,1)'需求。

根据输出需求的复杂程度,您可以将所有实例添加到数组中,然后让数组按希望的顺序输出值。这可以通过redim数组完成并保留每个返回值。 .Find循环完成后,使用Workbooks.Open方法打开一个新工作簿,然后运行一个快速循环,该循环将获取每个数组值并将其按您希望的顺序放置。

另一个选择是“打印”到.txt。打开一个新的.txt作为#1,然后相应地“打印”。也可以通过前面建议的array选项将其作为第二个子例程来完成。

希望这有助于为有关.FindNext方法的初始问题添加一些背景信息,并为将来的指导/实现提供一些思路。祝你好运!

Range.FindNext方法上的Microsoft页面: https://msdn.microsoft.com/en-us/VBA/Excel-VBA/articles/range-findnext-method-excel

答案 3 :(得分:0)

enter image description here

    Function FindMultiResut(ByRef What As String, _
                            ByRef FindRng As Range, _
                            ByRef OutputRng As Range, _
                            ByRef Delimite As String)

        Dim fRng As Range
        Dim Rng1 As Range
        Dim Rng2 As Range
        Dim temp As String

        Set fRng = FindRng
        Do
            If Rng1 Is Nothing Then
                Set Rng1 = fRng.Find(What:=What, After:=fRng(1))
                Set Rng2 = Rng1
            Else
                Set Rng2 = fRng.Find(What:=What, After:=Rng2)
                If Rng2.Address = Rng1.Address Then Exit Do
            End If

            If OutputRng.Worksheet.Cells(Rng2.Row, OutputRng.Column) <> Empty Then
                temp = temp & OutputRng.Worksheet.Cells(Rng2.Row, OutputRng.Column) & Delimite
            End If
        Loop
        FindMultiResut = Left(temp, Len(temp) - 1)
    End Function

答案 4 :(得分:0)

这是我在您的问题下的评论中提出的建议的实现。

git filter-branch

结束功能

它设计为UDF,因此您可以使用工作表函数(如git --no-replace-objects log)从工作表中调用它。您也可以使用类似代码的

来调用它
Function RowBeforeLast(ByVal What As Variant) As Long

Dim Fnd As Range

Set Fnd = Range("E:E").Find(What:=What, After:=Range("E1"), _
                            LookAt:=xlWhole, _
                            Searchdirection:=xlPrevious)
If Not Fnd Is Nothing Then
    Set Fnd = Range("E:E").Find(What:=What, After:=Fnd, _
                                LookAt:=xlWhole, _
                                Searchdirection:=xlPrevious)
    If Not Fnd Is Nothing Then RowBeforeLast = Fnd.Row
End If

无论哪种方式,它都会从列的底部返回第二次找到搜索条件的行号。如果仅发生一次或不发生,函数将返回零。