Excel VBA RangeオブジェクトのFindメソッドの使い方。
久しぶりにVBAの記事です。
特定の範囲の中から特定のデータを探すためのメソッド、Findの話です。
実は、先日はじめて使いました。
これが、かなり癖が強い。
Findの他にFindNextというのがあり、FindNextは「Find メソッドで開始された検索を 続行 します。」という説明が有るので、ファイルを探すDirのようなイメージで

こんな表にたいして
(このコードは無限ループします。)
(このコードは無限ループします。)
こんなふうに書いたら良いんじゃないかと思うと、注意書き通り無限ループします、、
なぜなら、指定された範囲内を検索し終わったらNothingが返るわけではなく、また同じ範囲を検索するのです、、
なので、一周したかを感知するには、最初に検索されたセルを覚えておいて、それと同じものが検索されてきたことでループを終わらせないといけないのです。
じゃぁ、これでいいでしょう。
と思うと、Debug.Printされる値は
$A$6
になります。
もう、わけがわかりません。
実は、FindNextというのは、After以外の引数が省略できるだけで、Findとやっていることは「全く」一緒なのです。
なので、Findで引数Afterを省略し、FindNextも引数無しで実行すると、指定された範囲の左上のセルの次から検索を行い、直前のFindと全く同じ結果が帰ってくるのです。
でも、だったら、
$A$3
になるんじゃない?とお思いでしょうが、上記でもサラッと書いたように、FindもFindNextも引数Afterを省略すると、指定された範囲の左上のセルから検索するのではなく、その次のセルから検索を始めるのです。
さらに、Afterを指定しても、その次のセルから検索を始めます。
ということで、FindNextには前回見つかったセルを渡せば次々と見つけてくれます。
こういうことですね。
これでも結果は
$A$6
$A$3
になってしまうので、上から順番に探してほしいなら、最初のFindでAfter:=Sheet1.Range("A8")の引数をつけるなどの工夫が必要になります。
いやぁ、なんかこれ、使いにくいぞ、、
また、手作業でセル範囲を選択して、Ctl-Fで出てくる「検索と置換」ダイアログとオプションを共有しているそうなので、Findの引数を省略すると、ダイアログの設定が引き継がれてしまって、動かすたびに動きが違うということになりかねないので、なるべく省略しないほうがいいそうです。
というか、「検索と置換」ダイアログそのものを動かしているように見えます。
うーん、VBAコードでセルを一つ一つ見ていくよりは速く動くんだろうけど、なんか嫌だなぁ、、
私の愛読書です。

できる大事典 Excel VBA 2016/2013/2010/2007対応 できる大事典シリーズ - 国本温子, 緑川吉行, できるシリーズ編集部

にほんブログ村
特定の範囲の中から特定のデータを探すためのメソッド、Findの話です。
実は、先日はじめて使いました。
これが、かなり癖が強い。
Findの他にFindNextというのがあり、FindNextは「Find メソッドで開始された検索を 続行 します。」という説明が有るので、ファイルを探すDirのようなイメージで

こんな表にたいして
(このコードは無限ループします。)
Sub TestA()
Dim targetRange As Range
Dim foundRange As Range
Set targetRange = Sheet1.Range("A3:A8")
Set foundRange = targetRange.Find("123")
Do Until foundRange Is Nothing
Debug.Print foundRange.Address
Set foundRange = targetRange.FindNext
DoEvents
Loop
End Sub
(このコードは無限ループします。)
こんなふうに書いたら良いんじゃないかと思うと、注意書き通り無限ループします、、
なぜなら、指定された範囲内を検索し終わったらNothingが返るわけではなく、また同じ範囲を検索するのです、、
なので、一周したかを感知するには、最初に検索されたセルを覚えておいて、それと同じものが検索されてきたことでループを終わらせないといけないのです。
Sub TestB()
Dim targetRange As Range
Dim foundRange As Range
Dim firstRange As Range
Set targetRange = Sheet1.Range("A3:A8")
Set foundRange = targetRange.Find("123")
Debug.Print foundRange.Address
Set firstRange = foundRange
Do
Set foundRange = targetRange.FindNext
If foundRange.Address = firstRange.Address Then
Exit Do
End If
Debug.Print foundRange.Address
DoEvents
Loop
End Sub
じゃぁ、これでいいでしょう。
と思うと、Debug.Printされる値は
$A$6
になります。
もう、わけがわかりません。
実は、FindNextというのは、After以外の引数が省略できるだけで、Findとやっていることは「全く」一緒なのです。
なので、Findで引数Afterを省略し、FindNextも引数無しで実行すると、指定された範囲の左上のセルの次から検索を行い、直前のFindと全く同じ結果が帰ってくるのです。
でも、だったら、
$A$3
になるんじゃない?とお思いでしょうが、上記でもサラッと書いたように、FindもFindNextも引数Afterを省略すると、指定された範囲の左上のセルから検索するのではなく、その次のセルから検索を始めるのです。
さらに、Afterを指定しても、その次のセルから検索を始めます。
ということで、FindNextには前回見つかったセルを渡せば次々と見つけてくれます。
Sub TestC()
Dim targetRange As Range
Dim foundRange As Range
Dim firstRange As Range
Set targetRange = Sheet1.Range("A3:A8")
Set foundRange = targetRange.Find("123")
Debug.Print foundRange.Address
Set firstRange = foundRange
Do
Set foundRange = targetRange.FindNext(foundRange)
If foundRange.Address = firstRange.Address Then
Exit Do
End If
Debug.Print foundRange.Address
DoEvents
Loop
End Sub
こういうことですね。
これでも結果は
$A$6
$A$3
になってしまうので、上から順番に探してほしいなら、最初のFindでAfter:=Sheet1.Range("A8")の引数をつけるなどの工夫が必要になります。
いやぁ、なんかこれ、使いにくいぞ、、
また、手作業でセル範囲を選択して、Ctl-Fで出てくる「検索と置換」ダイアログとオプションを共有しているそうなので、Findの引数を省略すると、ダイアログの設定が引き継がれてしまって、動かすたびに動きが違うということになりかねないので、なるべく省略しないほうがいいそうです。
というか、「検索と置換」ダイアログそのものを動かしているように見えます。
うーん、VBAコードでセルを一つ一つ見ていくよりは速く動くんだろうけど、なんか嫌だなぁ、、
私の愛読書です。

できる大事典 Excel VBA 2016/2013/2010/2007対応 できる大事典シリーズ - 国本温子, 緑川吉行, できるシリーズ編集部

にほんブログ村
この記事へのコメント