Excel VBA Range.FindNext v Range.Find - 我错过了啥?

Posted

技术标签:

【中文标题】Excel VBA Range.FindNext v Range.Find - 我错过了啥?【英文标题】:Excel VBA Range.FindNext v Range.Find - What have I missed?Excel VBA Range.FindNext v Range.Find - 我错过了什么? 【发布时间】:2018-03-04 10:30:44 【问题描述】:

问题: vba Range.FindNext v Range.Find - 我错过了什么?

(我对这里发帖还是不太熟悉,如有不对之处请见谅)

我一直在编写一些 VBA 代码,这些代码都是搜索长列的变体。 (通常它涉及连续查找许多事件,要么生成所有事件的列表,要么选择一个或多个(在执行 LookAt Part 类型选项时))

我不是计算机或编码专业人士,也没有太多经验,所以我错过了什么? …

在做我一直在做的事情时,与使用 .Find 相比,我期待 .FindNext 有一些优势。

举一个简化的例子,我想找到其中包含 rOh 的两个单词

    /      A       B        C
     1        
     2
     3             rOh3  
     4               
     5               
     6               
     7             rOh7  
     8               
     9               
    10              

所以我想要 Debug.Print 的输出

    rOh3
    rOh7

这是我见过的典型代码,也就是说我在互联网和教程中找到的代码:

    Sub VBAFindNext()
    Dim FirstrngFnd As Range, rngFnd As Range
     Set FirstrngFnd = Range("B1:B10").Find(What:="roh", LookAt:=xlPart)
        If FirstrngFnd Is Nothing Then Exit Sub
     Set rngFnd = FirstrngFnd
     Debug.Print FirstrngFnd.Value
        Do
         Set rngFnd = Range("B1:B10").FindNext(rngFnd)
        If Not rngFnd = FirstrngFnd Then Debug.Print rngFnd.Value
        Loop While Not rngFnd = FirstrngFnd
    End Sub

我在做这样的代码,看起来更简单,更灵活一些……

    Sub FindTheNext()
    Dim rngFnd As Range
     Set rngFnd = Range("B1:B10").Find(What:="roh", LookAt:=xlPart)
        If rngFnd Is Nothing Then Exit Sub
        Do While Not rngFnd Is Nothing
         Debug.Print rngFnd.Value
         Set rngFnd = Range("B" & rngFnd.Row + 1 & ":B10").Find(What:="roh", LookAt:=xlPart)
        Loop
    End Sub

所以我只是想知道我是否遗漏了什么? 我可以这样写后面的代码,但我没有看到任何改进

    Sub TheNextVBAFindNext()
    Dim rngFnd As Range
     Set rngFnd = Range("B1:B10").Find(What:="roh", LookAt:=xlPart)
        If rngFnd Is Nothing Then Exit Sub
        Do While Not rngFnd Is Nothing
         Debug.Print rngFnd.Value
         Set rngFnd = Range("B" & rngFnd.Row + 1 & ":B10").FindNext(rngFnd.Offset(1, 0))
        Loop
    End Sub

所以问题: 我希望有更多经验的人或对这些事情的工作有更深入了解的人可以解释任何可能使第一个代码更可取的原因。我可能在我的无知中遗漏了一些重要的东西。 我想具体的问题是“.FindNext 有什么意义”。是它只是节省了再次输入搜索条件,还是不止于此。 我可能天真地在想,对于一个很长的专栏,我的代码可能会更好一些,因为它每次看起来都在一个缩短的范围内,……但这是否属实将取决于我猜到底发生了什么“幕后” ”,我不知道。有其他人知道吗?如果可能的话,他们能用简单的术语解释一下吗?

谢谢

艾伦

附:我读到有些人认为 FindNext 坏了。但我还没有看到任何确凿的细节来证明这一点。

https://msdn.microsoft.com/de-de/vba/excel-vba/articles/range-findnext-method-excel https://msdn.microsoft.com/de-de/vba/excel-vba/articles/range-find-method-excel .FindNext failing after a .Find function (excel vba)

我拥有的实际代码通常要复杂得多,这就是为什么我试图更多地了解正在发生的事情: https://www.excelforum.com/excel-programming-vba-macros/1186516-smarter-search-process.html#post4664009

【问题讨论】:

你的第一个代码得到你想要的值,我运行它找到值并在调试器窗口中打印它们,你到底有什么问题? @Foxfire And Burns And Burns 谢谢回复。所有代码都有效。第二个代码是我的。第一个代码是通常给出或建议的代码,并使用 FindNext 。我试图理解为什么会使用 FindNext。我不是程序员。我想知道我的(第二个)代码是否愚蠢。我试图理解为什么会使用 FindNext。我从互联网上阅读了大量博客的所有文档。我看不出使用它的理由。我错过了什么? FindNext 似乎是多余的/不必要的。为什么不像我在(第二个)代码中那样使用 Find?没有文档答案。所以我想我会在这里问这一切。 :) 2018 年 3 月 9 日编辑:只是为了澄清。 Ist 代码是通常在网络上给出的代码。代码2是我一直在使用的。它使用 Find 和 Find,(代码中的两个 oiccurances)。代码 3 类似于代码 2,但使用 Find 和 FindNext。实际上代码 2 和代码 3 并没有像我想要的那样工作。我的代码子 FindTheNext2() (德国时间 3 月 8 日回答 - 我的第二个帖子 - 一个回答 - 我的第一个回答)是我终于满意的那个。 :) 【参考方案1】:

好的,我现在明白你的意思了。在我看来:

查找:此方法将允许您使用您定义的参数开始搜索。每次调用 Find 时,您都在创建一个新的搜索过程。

FINDNEXT:此方法将继续使用以前的 Find 方法开始搜索,节省再次输入参数的时间,并更新搜索范围(实际上,在您的第二个和第三个代码中,您使用Range("B" & rngFnd.Row + 1 & ":B10")更新您正在搜索的范围。使用FindNext,搜索范围始终相同(在您的示例中,它是B1:B10),但VBA会记住最后一个位置并从最后一个位置继续搜索位置。

那么重点是什么?好吧,除非您设置断点,否则这两种方法都会创建一个无限循环。在您的第一个代码中,断点位于Loop While Not rngFnd = FirstrngFnd 行中。 VBA 会记住它搜索的第一个范围以及当再次循环到该范围时,它会中断循环并恢复代码。您的第二个和第三个代码是无限循环。他们永远不会停止执行。试试看。

如果您在第二个和第三个代码中设置了类似的断点,它们将不起作用,因为您一直在更新要搜索的范围,因此它无法在使用条件找到的第一个范围内进行搜索, 就会无限循环(其实无限循环会一直在B10:b10中搜索)。

要设置有效的断点,您需要两种方法。为什么?因为正如我在文章开头所说的,Find 每次调用它时都会开始一个新的搜索,所以它不会移动,你会再次创建一个无限循环。为确保您的搜索进入满足定义条件的下一个范围,您需要使用FindNext

我希望这个答案可以让您了解这两种方法如何协同工作。无论如何,您可以在此处阅读有关此的更多信息:

Range.Find Method (Excel)

Range.FindNext

【讨论】:

@ Foxfire And Burns And Burns 再次感谢您的回复。我认为这证实了我对这些事情的理解,但是文档很少,所以最好让知道的人说出来。 (我的帖子中有这些链接)。代码 2 和 3 有一个断点(Loop While Not rngFnd Is Nothing)所有代码都有效。无无限循环(除非在代码 2 和 3 中在最后一个单元格中找到某些内容的情况下,它们会无限循环。但在我实际的大文件中,确保最后一个单元格为空是没有问题的)。再次感谢。艾伦 只是为了澄清我对代码 2 和 3 的推理,以及它们看起来如何正常工作(没有进入无限循环)——“可能会发现一些东西向下搜索”。 (如果从来没有,那么在循环之前我有 Exit Sub)。当找到某物时,下一个搜索范围从该物被发现的位置开始。最终什么也没找到,所以断点( Loop While Not rngFnd Is Nothing )开始了。我必须确保最后一个单元格是空的,这样如果在最后一个单元格中找到了一些东西,那么下一个搜索范围(最后一个单元格)给出 rngFnd 什么都不是 编辑:事实上我什至不需要 If rngFnd Is Nothing Then Exit Sub 因为我的 Do While Not rngFnd Is Nothing 会阻止任何事情发生一无所获 再次澄清。我的代码(我的第一篇文章中的第二个 2 代码)仅在最后一个单元格( B10 )中找到某些东西的情况下无限循环。在这种情况下,下一个要搜索的范围是 B11:B10。然后会再次找到 B10 中的东西,下一个要搜索的范围是 B11:B10 .. 依此类推……我现在尝试在下面澄清/回答..【参考方案2】:

我认为这是我目前能找到的最接近答案的地方..

_1) 如果您使用 FindNext,您不需要再次提供搜索条件这一事实可能并不是特别有趣。

_ 2 对于 FindNext 某处 VBA 记住最后找到的单元格的位置这一事实可能不是特别有利。如果您按照我在下面代码中所做的方式使用 .Find,那么您可以实现相同的效果,并且参数中的额外文本可能有助于跟踪代码中正在执行的操作..

_3) 我怀疑 FindNext 可能是为了避免像我在我的代码中那样陷入陷阱(我的第一篇文章中的后两个..):在进一步的实验中,我发现这两个代码没有' t 实际上做我想做的事。

例如,如果这是我的测试范围:_...

    /      A       B        C
     1             rOh1
     2             rOh2
     3             rOh3  
     4               
     5               
     6               
     7             rOh7  
     8             rOh8   
     9             rOh9     
    10              

_.. 然后我的代码输出(我第一篇文章的后两个)是

    rOh2
    rOh7
    rOh9

问题是我编写的代码不允许我从范围内的第一个单元格开始 - 如果我没有指定 After:= 参数,.Find 的编写方式是它开始查找左上角之后。

如果我确实指定了 After:= 参数,那么它必须在搜索范围内。因此,我无法在调整后的搜索范围之前指定 After:=。好吧,实际上我可以:),有点:

我的下一个代码是做生意的。只需始终从 After:= 范围中的最后一个单元格开始。 – 正如 Foxfire 和 Burns 和 Burns 提醒我们的那样,.Find(和 .FindNext)会继续运行——当它们到达搜索范围的尽头时,它们会重新开始。通过指定 After:= 最后一个单元格,则搜索始终从搜索范围中的第一个单元格开始。在我的代码中,搜索范围更新为从最后一个找到的单元格开始的范围。

可能值得注意的是,常规代码(我给出的第一个代码)虽然运行良好,但对于我在这篇文章中给出的测试数据范围,它会给出以下内容:

    rOh2
    rOh3
    rOh7
    rOh8
    rOh9
    rOh1

您会看到它最后找到了“第一个匹配项”。如果您没有意识到这一点,我预计这可能会引起一些混乱。

所以下面我修改的简化代码似乎最适合我使用。它给出了

的输出
    rOh1
    rOh2
    rOh3
    rOh7
    rOh8
    rOh9

这里是代码,注意最后一个单元格应该是空的

    Sub FindTheNext2()
    Dim rngFnd As Range
     Set rngFnd = Range("B1:B10").Find(What:="roh", after:=Range("B10"), LookAt:=xlPart)
        If rngFnd Is Nothing Then Exit Sub
        Do While Not rngFnd Is Nothing
         Debug.Print rngFnd.Value ' Do anything you wanna do                                                                                         http://www.youtuberepeater.com/watch?v=8GoN-y9irn4&name=Eddie+and+the+Hot+Rods+Do+anything+you+wanna
         Set rngFnd = Range("B" & rngFnd.Row + 1 & ":B10").Find(What:="roh", after:=Range("B10"), LookAt:=xlPart)
        Loop
    End Sub

如果最后一个单元格可能被使用,那么此代码将处理该问题:

    Sub FindTheNext3()
    Dim rngFnd As Range
     Set rngFnd = Range("B1:B10").Find(What:="roh", after:=Range("B10"), LookAt:=xlPart)
        Do While Not rngFnd Is Nothing
         Debug.Print rngFnd.Value ' Do anything you wanna do                                                                                         http://www.youtuberepeater.com/watch?v=8GoN-y9irn4&name=Eddie+and+the+Hot+Rods+Do+anything+you+wanna
            If rngFnd = Range("B10") Then Exit Sub
         Set rngFnd = Range("B" & rngFnd.Row + 1 & ":B10").Find(What:="roh", after:=Range("B10"), LookAt:=xlPart)
        Loop
    End Sub

如果 Findnext 可能有任何更深入的技术原因,那么我怀疑任何人都记得。

我认为我的底线是不要打扰它,我看不出它有什么价值

问题:…… VBA Range.FindNext v Range.Find - 我错过了什么?

回答:…… 没什么,FindNext 是一种令人困惑的浪费时间。只需使用 .Find 并确保您确切知道它是如何工作的。

【讨论】:

以上是关于Excel VBA Range.FindNext v Range.Find - 我错过了啥?的主要内容,如果未能解决你的问题,请参考以下文章

excel vba 运行时错误

java 调用excel vba

选了一门叫excel vba的课,是干啥的

excel vba 运行速度慢

Excel 请问如何破解VBA工程不可查看

excel vba 调用ADODB 问题?