简体   繁体   English

查找和查找下一个 Excel VBA

[英]Find and FindNext for Excel VBA

I've been stuck trying to figure out what to do with this, but basically I want a way to print out the value in column B given a specific value that matches column A. So for example:我一直在试图弄清楚如何处理这个问题,但基本上我想要一种方法来打印出 B 列中的值给定与 A 列匹配的特定值。例如:

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

I want to, after using find/findnext or whatever it is, to print out this string:我想在使用 find/findnext 或其他任何东西后打印出这个字符串:

ABC JKL

I tried using我尝试使用

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

And I have a loop to loop through as many time as it needs to get all the rows taken care of.我有一个循环来循环尽可能多的时间来处理所有行。 But with find it keeps returning me the same first string ("ABC") and the string ends up being ABC ABC instead of ABC JKL但是随着 find 它不断返回相同的第一个字符串(“ABC”)并且该字符串最终是 ABC ABC 而不是 ABC JKL

I tried using FindNext instead of find, but what I got is a 1004 Error.我尝试使用 FindNext 而不是 find,但我得到的是 1004 错误。 So I'm not really sure where I'm doing this wrong.所以我不确定我在哪里做错了。 Anyone has any idea?任何人有任何想法?

You don't need FindNext if you start each Find after the previous one:如果在上一个Find之后开始每个Find ,则不需要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

在此处输入图片说明

You need to call Find once, and then successively FindNext需要调用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

Reference:参考:

When using the Range.FindNext method, one need just include some reference to the initial find position.使用 Range.FindNext 方法时,只需要包含对初始查找位置的一些引用。 For example, I recorded this macro using excel;比如我用excel记录了这个宏; while I'm not a fan of using selection and activate, I think it helps to understand how the method functions:虽然我不喜欢使用选择和激活,但我认为理解该方法的功能会有所帮助:

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

To generate this subroutine, I used the record > macro in excel, then selected Home > Find & Select > Find.为了生成这个子程序,我在excel中使用了record > macro,然后选择了Home > Find & Select > Find。

The way I see this subroutine working is:我看到这个子程序工作的方式是:

Step #1: Find the first location of the string, activate it;步骤#1:找到字符串的第一个位置,激活它;

Step #2: FindNext looks after the active cell that we just activated, finds the next location of the string, then activates it;第2步:FindNext中查找活动单元格,我们刚刚启动,找到了这个字符串的下一个位置,然后激活它;

Etc. etc. So, the observation here is that the .FindNext method needs some reference to the prior find cell (which the first answer accomplishes by manually identifying it as a unique reference).等等等等。所以,这里的观察是 .FindNext 方法需要对先前查找单元格的一些引用(第一个答案通过手动将其识别为唯一引用来完成)。 I'm not saying anything to that answer, it works just as well.我对那个答案没有说什么,它也同样有效。 My goal was to help provide some insight into the Range.FindNext method.我的目标是帮助深入了解 Range.FindNext 方法。

Some other points worth mentioning:还有一些值得一提的点:

Range.FindNext will return a Range object. Range.FindNext 将返回一个Range对象。 (Microsoft) (微软)

The After parameter is described as: After参数描述为:

"The cell after which you want to search. This corresponds to the position of the active cell when a search is done from the user interface. Be aware that After must be a single cell in the range. Remember that the search begins after this cell; the specified cell is not searched until the method wraps back around to this cell. If this argument is not specified, the search starts after the cell in the upper-left corner of the range." "您要搜索的单元格。这对应于从用户界面进行搜索时活动单元格的位置。请注意,After 必须是范围内的单个单元格。请记住,搜索在此单元格之后开始; 指定的单元格不会被搜索,直到该方法返回到该单元格。如果未指定此参数,则搜索在范围左上角的单元格之后开始。" (Microsoft) (微软)

...and ...和

Under the Remarks section, Microsoft notes that, "The search will wrap around to the beginning of the range."备注部分,微软指出,“搜索将环绕到范围的开头。” They suggest to save the first address and do a check against it for each subsequent .FindNext.他们建议保存第一个地址,并为每个后续的 .FindNext 进行检查。 This way, once the method does wrap around, it will check the address against the first and end the check.这样,一旦该方法执行回绕,它将根据第一个地址检查地址并结束检查。

So, modeling the Range.FindNext Method provided by Microsoft, I wrote this introductory subroutine for review:所以,建模微软提供的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

To adjust this code to your specific needs, we can change the sentence after the Do line: 'MsgBox c.Offset(0,1)' to our specific needs.要根据您的特定需求调整此代码,我们可以根据我们的特定需求更改Do之后的句子:'MsgBox c.Offset(0,1)'。

Depending on how complex your output needs are, you can add all occurrences to an array, then have the array output the values in order of how you want to see them.根据您的输出需求的复杂程度,您可以将所有出现的事件添加到一个数组中,然后让数组按照您希望如何查看它们的顺序输出值。 This can be done by redim array and preserve each return.这可以通过 redim 数组完成并保留每个返回。 Once the .Find loop completes, open a new workbook with the Workbooks.Open method, and run a quick loop that takes each array value and places it in the order that you prefer. .Find 循环完成后,使用 Workbooks.Open 方法打开一个新工作簿,然后运行一个快速循环,获取每个数组值并将其按您喜欢的顺序放置。

Another option is to 'print' to .txt.另一种选择是“打印”到 .txt。 Open a new .txt as #1, then 'print' accordingly.打开一个新的 .txt 作为 #1,然后相应地“打印”。 This can also be done as a second subroutine via the array option suggested previously.这也可以通过前面建议的数组选项作为第二个子程序来完成。

Hope this helps add some context to your initial question with respect to the .FindNext method, as well as provides some ideas for future direction/implementation.希望这有助于为您关于 .FindNext 方法的初始问题添加一些上下文,并为未来的方向/实现提供一些想法。 Good luck!祝你好运!

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

在此处输入图片说明

    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

Here is an implementation of the suggestion I made in my comment under your question.这是我在您的问题下的评论中提出的建议的实施。

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

End Function结束函数

It's designed as a UDF so that you can call it from the worksheet with a worksheet function like =RowBeforeLast(E5) .它被设计为 UDF,因此您可以使用工作表函数(如=RowBeforeLast(E5)从工作表中调用它。 You can also call it with code like你也可以用像这样的代码来调用它

Private Sub TestGet()
    RowBeforeLast "GR 3"
End Sub

Either way it will return the row number in which the search criterium was found for the second time from the bottom of the column.无论哪种方式,它都会返回从列底部第二次找到搜索条件的行号。 If there is only one or no occurrance the function will return zero.如果只有一次或没有出现,该函数将返回零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM