VBAで、条件に当てはまるセルを検索するメソッドなら、Findがお馴染みです。
ただ、別にこの関数を使わなくても、For~Nextによる配列で検索もできます。
以前の投稿でその方法を紹介しましたが、一方、Findならば検索に融通が利く。
要するに、検索でも、完全一致、部分一致、それに複数の一致までできるんだ。
しかも、使い方で豊富な引数から検索条件を細かく指定できるのが、ミソです。
面白いと思うのは、検索対象をセルのコメント文や数式まで指定できるところ。
検索する方向も行あるいは列で指定したり、検索する順番も上から下から指定。
大文字と小文字、半角字と全角字を区別できたり、条件の玉手箱みたいなんだ。
だから、ついついFindメソッドを使いまくりますが、使うのが下手で動かない。
思うに、検索して見つかるセルが複数ある時のプログラム構文が変な感じです。
なので、ネットで紹介している構文を探しまくって、自分なりの理解があった。
それは、FindとFindNextのメソッドも含めて検索作業を先ず終わらせること。
次に、見つかった複数セルの位置を配列に格納しておいて次の作業で引用する。
この配列なのですが、見つかるセル位置の要素数は、定まっていないのが厄介。
中には、動的配列で要素数を意識せずに拡張する紹介もあったのだが複雑だな。
なので、セル限定で配列を作るUnionコマンドで、検索されたセルを格納です。
一方、VBA専門のブログでも、FindにこのUnionを組合せた紹介がありました。
でも、紹介されたのは、使い道を見出しにくいサンプルで自分なりに工夫した。
このUnionコマンドは、複数のRangeオブジェクトを連結できて切取りもOK。
連結したオブジェクトの個数や何番目のオブジェクトか、アドレス取得も可能。
要は、Findによる複数検索結果のアドレスが格納できて、スグレモノだろうな。
だから、Unionの値を変数にしてCallステートメントの変数渡しにしてしまう。
こうすれば、検索結果を次のプロシージャで処理できる記述が書きやすくなる。
というわけで、サンプル構文を紹介しておきますので、参考になればいいなあ。
実を言うと、このUnionコマンドは、実際のプログラミングで使った見たことがなかったのですが、今回のサンプル構文に利用したことで、Findメソッドを検索だけの機能に簡素化集約しておいて、複数の検索結果は別のプシージャで処理できるようになった点で、コードが複雑にならず、可読性が高まったなとおもうのでした。
<サンプル構文>
Sub FndNxtUnon()
Dim FndCll As Range, FrstCll As Range, Trgt As Range, SrchRng As Range
Set SrchRng = Range("B:B") '検索する範囲をB列で設定
Set FndCll = SrchRng.Find(What:="HogeHoge") '最初はFindで検索
If FndCll Is Nothing Then
MsgBox "見つかりません"
Exit Sub
Else
Set FrstCll = FndCll
Set Trgt = FndCll '最初の検索結果を別名の変数に置き換え一時保存
End If
Do '条件なしのDo~Loopなのでループを抜ける設定が必ず必要
Set FndCll = Cells.FindNext(FndCll) 'FindNextで検索を継続
If FndCll.Address = FrstCll.Address Then
Exit Do ' 最初の検索結果と同じなら、それだけなのでループ脱出
Else
Set Trgt = Union(Trgt, FndCll) ' 見つかった範囲を格納していく
End If
Loop
Trgt.Select
MsgBox Trgt.Count & "件見つかりました"
Call UnionFctrGet(Trgt) ' CallステートメントでUnionの値を変数渡し
End Sub
Sub UnionFctrGet(ByVal Trgt As Range)
Dim k As Long
For k = 1 To Trgt.Areas.Count ' 検索結果の個数でループ処理
Debug.Print Trgt.Areas(k).Row ' k番目の検索結果の行(値)を書き出し
Next k
End Sub
0 件のコメント:
コメントを投稿