セルの検索を同じ条件で続けて検索する
セルの検索はFindメソッドで行います。Findメソッドを実行したときと同じ検索条件で次のセルの検索を行う場合はFindメソッドではなく、FindNextメソッドを使います。前のセルの検索を行う場合はFindPreviousメソッドを使います。
よって、FindNextメソッドとFindPreviousメソッドは事前にFindメソッドを実行しておく必要があります。Findメソッドの詳細については「VBAでセルの検索を行う(Findメソッド)」をご参照ください。
Findメソッドには9個の引数がありますが、FindNextメソッドとFindPreviousメソッドはそれらの引数を内部的に引き継いでいるため引数を省略して実行できます。
検索を開始する単一セルのみを引数に指定することが可能です。
構文
Function Range.FindNext([After]) As Range
Function Range.FindPrevious([After]) As Range
Range 親オブジェクト |
検索範囲のRangeオブジェクト |
After (省略可) |
親オブジェクトで指定した検索範囲内に含まれている単一セルを指定します。
ここで指定したセルは検索対象にならず、次のセルから検索が行われます。 それらの検索が終わったあとにここで指定したセルが検索されます。 省略した場合は親オブジェクトで指定した検索範囲の中で一番左上にあるセルになります。 親オブジェクトのRangeのセル範囲にここで指定したセルが含まれていない場合はエラーになります。 |
戻り値 Range |
検索条件に一致するセルが見つかった場合はそのセルのRangeオブジェクトを返します。見つからなかった場合はNothingを返します。 |
戻り値のNothing判定処理
FindNext、FindPreviousメソッドより先に実行するFindメソッドを使う場合、検索に一致するセルが見つからないと戻り値にNothingを返します。
そのため、Findメソッドの戻り値がNothingかどうかの判定が必須になります。
ではFindNext、FindPreviousメソッドの場合はどうかというと、やはりNothingの判定は入れておいた方が無難です。
正確に言えば、FindメソッドでNothingでないのであればFindNextとFindPreviousメソッドでNothingになることはないのですが、レアケースで以下のような条件の場合はNothingになります。
- Findメソッドの途中にセルの内容を書き換えるような処理がある場合
- 検索に一致するセルが1つしかなく、かつ、そのセルが縦に結合されている場合
このような場合が無いとは限らないため、Findメソッドと同様にNothingの判定は入れておきましょう。
検索の無限ループを防ぐには
Findメソッド、FindNextメソッド、FindPreviousメソッドのいずれも、検索範囲の最後まで検索すると、また検索範囲の開始セルから検索を行います。
そのため同じセルが何度も検索されることになります。
これを防ぐには最初のFindメソッドで見つかったセルを保持しておき、このセルが再度検索されたかどうかを判定して検索の無限ループを回避します。
引数Afterの省略と設定の基準
Find、FindNext、FindPreviousの各メソッドのいずれにも、検索の基準となる単一セルを引数Afterで指定します。
引数Afterは省略した方がいい場合とそうでない場合があります。
具体的には、Findメソッドの引数Afterは省略して、FindNextとFindPreviousメソッドは省略しない方がコーディングは楽になります。
Findメソッドの場合は親オブジェクトのRangeオブジェクトで指定する検索範囲の中に引数Afterがない場合にFindメソッドがエラーになります。
省略した場合は検索範囲の中で一番左上のセルが開始位置になります。
その省略時の仕様に従った方がコーディングはしやすくなります。
またFindNextとFindPreviousメソッドで引数Afterを省略すると事前のFindメソッドで検索したセルが引き継がれないことになります。
以下のサンプルコードでもFindメソッドのAfterは省略し、FindNextとFindPreviousメソッドは省略せずにコーディングしています。
FindNextのサンプルコード
まずFindメソッドを実行して、あとは同じ検索条件でFindNextメソッドを行うサンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
Sub FindNextTest() Dim rStart As Range '// 最初に検索されるセル Dim rNext As Range '// FindNextで検索されるセル Dim sSearch As String '// 検索文字列 sSearch = "aa" '// セルを検索 Set rStart = Cells.Find( _ What:=sSearch, _ LookIn:=xlFormulas, _ LookAt:=xlPart, _ SearchOrder:=xlByRows, _ SearchDirection:=xlNext, _ MatchCase:=False, _ MatchByte:=False, _ SearchFormat:=False) '// 検索不一致時は処理を終了 If rStart Is Nothing Then Exit Sub End If Debug.Print rStart.Address '// 次の検索の初期Rangeオブジェクトとして設定 Set rNext = rStart Do '// 次を検索 Set rNext = Cells.FindNext(After:=rNext) '// 検索不一致時はループを抜ける If rNext Is Nothing Then Exit Do End If '// 最初に検索されたセルが再検索された場合 If rNext.Address = rStart.Address Then Exit Do End If Debug.Print rNext.Address Loop End Sub |
実行結果
FindメソッドはA1セルが基点となり、次のセルはB2セルが検索一致になります。
$B$2
$B$3
$D$3
$C$4
$A$5
$A$1
FindPreviousのサンプルコード
まずFindメソッドを実行して、あとは同じ検索条件でFindPreviousメソッドを行うサンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
Sub FindPreviousTest() Dim rStart As Range '// 最初に検索されるセル Dim rPrevious As Range '// FindPreviousで検索されるセル Dim sSearch As String '// 検索文字列 sSearch = "aa" '// セルを検索 Set rStart = Cells.Find( _ What:=sSearch, _ LookIn:=xlFormulas, _ LookAt:=xlPart, _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious, _ MatchCase:=False, _ MatchByte:=False, _ SearchFormat:=False) '// 検索不一致時は処理を終了 If rStart Is Nothing Then Exit Sub End If Debug.Print rStart.Address '// 前の検索の初期Rangeオブジェクトとして設定 Set rPrevious = rStart Do '// 次を検索 Set rPrevious = Cells.FindPrevious(After:=rPrevious) '// 検索不一致時はループを抜ける If rPrevious Is Nothing Then Exit Do End If '// 最初に検索されたセルが再検索された場合 If rPrevious.Address = rStart.Address Then Exit Do End If Debug.Print rPrevious.Address Loop End Sub |
実行結果
FindメソッドはA1セルが基点となり、前のセルはA5セルが検索一致になります。
$A$5
$C$4
$D$3
$B$3
$B$2
$A$1