[[20090225013003]] 『EXCEL VBA Findで逆方向に検索』(たちお) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『EXCEL VBA Findで逆方向に検索』(たちお)Excel2003,WindowsXP
 sheet1のA列に"■"がランダムに入力されています("■"以外の値も混在)。
 A列の任意のセルをアクティブにした状態から、
 上下方向に次の"■"を検索したいです。
 下方向に検索する場合は下記コードで検索できましたが、
 上方向に検索する場合はどの様にコードを改修すれば良いのでしょうか?
 ご教授お願い致します。

 尚、FindではなくDo〜Loop Untilで、
 セル値を"■"にヒットするまで1個づつ検索していく方法であれば、
 上方向の検索もできたのですが、出来ればFindで実現したいです。
 (処理時間が短くなる(?)と思うので…)

 Sub 次の■へジャンプ()

 Dim nowcell_add As String '現在のアドレス
 Dim nowcell_row As Integer '現在の行
 Dim nowcell_col As Integer '現在の列

 Dim nextbox As Variant '次の■のセル
 Dim nextbox_add As String '次の■のアドレス

 Dim last_row As Integer '最終行

 nowcell_add = ActiveCell.Address
 nowcell_row = ActiveCell.Row
 nowcell_col = ActiveCell.Column
 last_row = Cells(Rows.Count, 1).End(xlUp).Row

 If (nowcell_row < last_row) And (nowcell_col = 1) Then
     Set nextbox = Range(Cells(nowcell_row, 1), Cells(last_row, 1)).Find("■")
     If Not nextbox Is Nothing Then
         nextbox_add = nextbox.Address
         Range(nextbox_add).Select
     End If
 End If
 End Sub

 私は、Findメソッド扱いが面倒なので、これをラップしたプロシジャーを先に作ってしまっています。

 新規ブックにて試してみてください。

 まず、コードから、標準モジュール(module1)にサンプルデータ作成プロシジャー

 '============================================================================
 Option Explicit
 Sub mk_sample()
    With Range("a1:a100")
       .Formula = "=int(rand()*10)"
       .Value = .Value
    End With
 End Sub

 別の標準モジュール(Module2)に上下検索プロシジャー

 '==================================================================
 Sub main()
    Const 検索値 = 1
    Dim ans As Long
    Dim strng As Range
    Dim rng As Range
    With Range("a1:a100")
       ans = MsgBox("検索方向 はい →下 いいえ→上", vbYesNo)
       If ans = 6 Then
          Set strng = get_strng(ActiveCell, .Cells, xlNext)
          If strng Is Nothing Then
             MsgBox "検索位置が不正です"
             Exit Sub
          Else
            Set rng = get_findcell(検索値, .Cells, strng, xlValues, xlWhole, xlByColumns, xlNext)
          End If
       Else
          Set strng = get_strng(ActiveCell, .Cells, xlPrevious)
          If strng Is Nothing Then
             MsgBox "検索位置が不正です"
             Exit Sub
          Else
             Set rng = get_findcell(検索値, .Cells, strng, xlValues, xlWhole, xlByColumns, xlPrevious)
          End If
       End If
       Do Until rng Is Nothing
         rng.Select
         MsgBox "ok"
         Set rng = get_findcell
       Loop
    End With
 End Sub
 '=======================================================================================
 Function get_strng(chkrng As Range, f_rng As Range, Optional ByVal asd As XlSearchDirection = 1) As Range
'検索開始位置をチェックする
    On Error Resume Next
    Set get_strng = Nothing
    If Not Application.Intersect(chkrng, f_rng) Is Nothing Then
       If asd = xlNext Then
          If chkrng.Row = f_rng.Cells(1, 1).Row Then
             Set get_strng = f_rng.Cells(f_rng.Rows.Count, f_rng.Columns.Count)
          Else
             Set get_strng = chkrng.Offset(-1, 0)
          End If
       Else
          If chkrng.Row = f_rng.Cells(f_rng.Rows.Count, f_rng.Columns.Count).Row Then
             Set get_strng = f_rng.Cells(1, 1)
          Else
             Set get_strng = chkrng.Offset(1, 0)
          End If
       End If
    End If
 End Function

 又、別の標準モジュール(Module3)にFindメソッド汎用プロシジャー

 '================================================================================
 Function get_findcell(Optional ByVal f_v As Variant = "", _
                      Optional ByVal rng As Range = Nothing, _
                      Optional ByVal strng As Range = Nothing, _
                      Optional ByVal alookin As XlFindLookIn = -4163, _
                      Optional ByVal alookat As XlLookAt = 1, _
                      Optional ByVal aso As XlSearchOrder = 1, _
                      Optional ByVal asd As XlSearchDirection = 1, _
                      Optional ByVal mc As Boolean = False, _
                      Optional ByVal mb As Boolean = True) As Range
 '指定された値でセル範囲を検索し、該当するセルを取得する
 'input : f_v 検索する値
 '    rng 検索する範囲
 '       strng 検索開始するセル(実際には、このセルの次から検索する)
 '    alookin 検索対象 xlvalues,xlformulas,xlcomments
 '    alookat: :検索方法 1-完全一致 2-部分一致
 '    aso : 検索順序 1 行 2 列
 '    asd : 検索方向 1 Xlnext 2 XlPrevious
 '    mc  : 大文字・小文字の区別 False しない True する
 '    mb  : 半角と全角を区別   True する  False しない
 'output:get_findcell 見つかったセル(見つからなかったときはNothingが返る)
    Static 検索範囲 As Range
    Static 最初に見つかったセル As Range
    Static 直前に見つかったセル As Range
    Static 検索方向 As XlSearchDirection
    If Not rng Is Nothing Then
       Set 検索範囲 = rng
       If strng Is Nothing Then
          If asd = 1 Then
             Set strng = 検索範囲.Cells(検索範囲.Rows.Count, 検索範囲.Columns.Count)
          Else
             Set strng = 検索範囲.Cells(1, 1)
          End If
       End If

    End If
    If f_v <> "" Then
       Set get_findcell = 検索範囲.Find(f_v, strng, alookin, alookat, aso, asd, mc, mb)
       If Not get_findcell Is Nothing Then
          Set 最初に見つかったセル = get_findcell
          Set 直前に見つかったセル = get_findcell
          検索方向 = asd
       End If
    Else
       If 検索方向 = xlNext Then
          Set get_findcell = 検索範囲.FindNext(直前に見つかったセル)
       Else
          Set get_findcell = 検索範囲.FindPrevious(直前に見つかったセル)
       End If
       If get_findcell.Address = 最初に見つかったセル.Address Then
          Set get_findcell = Nothing
       Else
          Set 直前に見つかったセル = get_findcell
       End If
    End If
 End Function

使用方法

 まず、mk_sampleを実行してみてください。
 セル範囲A1:A100に0〜9の値がランダムに設定されます。
 mainプログラムは、この中の1を検索する機能を持ちます。

 A1:A100のセル範囲の中の適当なセルを選択した状態でプロシジャーmainを実行してください。

 「検索方向 はい →下 いいえ→上」というメッセージが表示されます。

 はい を選択すれば、選択したセルから下に1のあるセルを順次選択します。

 いいえ を選択すれば、選択したセルから上に1のあるセルを順次選択します。

 作動することを確認されたら、検索セル範囲や検索文字を変更して試してみてください。

 もっとも、検索速度だけを重視すれば、Findメソッド以外の方法に目を向けるのも
 良いかもしれませんよ!!

 ichinose


 >ichinose殿
 早速のご解答有難う御座います。
 ご提案頂いたプログラムの動作確認させて頂きました。
 自分はまだまだ知識不足の為、
 構文を読み下すには時間がかかりそうなので、
 取り急ぎお礼まで。
 因みに、
 「検索速度だけを重視すれば、Findメソッド以外の方法…」とは、
 例えばどんなモノがあるのでしょうか?

 (たちお)


 >因みに、
 >「検索速度だけを重視すれば、Findメソッド以外の方法…」とは、
 >例えばどんなモノがあるのでしょうか?
 VBAと数式を使って検索値を探す方法なんて考えられます。

 検討してみてください。

 ichinose


 すでに解決されたようですが、

 逆方向の検索は、Find に
 SearchDirection:=xlPrevious
 を追加するだけです。
http://excelvba.pc-users.net/fol7/7_1.html

 パフォーマンスに関してですが、EXCEL が用意している関数は、
 同等のものをコードで書いたものに比べても高速である場合も
 あるようです。
http://officetanaka.net/excel/vba/speed/s9.htm
 (Mook)

 たちおさんへ
 休みになったので、数式を使った例です。

 新規ブックにて試してみてください。

 まず、コードから、標準モジュール(module1)にサンプルデータ作成プロシジャー
 これは、前回投稿と同じです。

 '============================================================================
 Option Explicit
 Sub mk_sample()
    With Range("a1:a100")
       .Formula = "=int(rand()*10)"
       .Value = .Value
    End With
 End Sub

 別の標準モジュール(Module2)に上下検索プロシジャー

 '================================================================== 
 Sub main()
    Const 検索値 = 1
    Dim g0 As Long
    Dim ans As Long
    Dim strng As Range
    Dim myarray As Variant
    Dim stind As Long
    Dim edind As Long
    Dim stepnum As Long
    With Range("a1:a100")
       If Not Application.Intersect(ActiveCell, .Cells) Is Nothing Then
          ans = MsgBox("検索方向 はい →下 いいえ→上", vbYesNo)
          If ans = 6 Then
             Set strng = .Range(ActiveCell, .Cells(.Rows.Count))
          Else
             Set strng = .Range(.Cells(1), ActiveCell)
          End If
          With strng
             MsgBox "transpose(if(" & .Address & "=" & 検索値 & _
                            ",row(" & .Address & "),""" & Chr(&HFF) & """))" _
                    & vbCrLf & "こんな数式を評価します"
             '↑これは、確認したら、コメント化してください
             myarray = Evaluate("transpose(if(" & .Address & "=" & 検索値 & _
                             ",row(" & .Address & "),""" & Chr(&HFF) & """))")
             If Not IsArray(myarray) Then myarray = Array(myarray)
             myarray = Filter(myarray, Chr(&HFF), False)
          End With
    Else
       Exit Sub
       End If
    End With
    If UBound(myarray) >= 0 Then
       If ans = 6 Then
          stind = LBound(myarray)
          edind = UBound(myarray)
          stepnum = 1
       Else
          stind = UBound(myarray)
          edind = LBound(myarray)
          stepnum = -1
       End If
       For g0 = stind To edind Step stepnum
          Range("a" & myarray(g0)).Select
          MsgBox "ok"
       Next
    End If
 End Sub

使用方法

 まず、mk_sampleを実行してみてください。
 セル範囲A1:A100に0〜9の値がランダムに設定されます。
 mainプログラムは、この中の1を検索する機能を持ちます。

 A1:A100のセル範囲の中の適当なセルを選択した状態でプロシジャーmainを実行してください。

 「検索方向 はい →下 いいえ→上」というメッセージが表示されます。

 はい を選択すれば、選択したセルから下に1のあるセルを順次選択します。

 いいえ を選択すれば、選択したセルから上に1のあるセルを順次選択します。

 若干、仕様を変更しましたが、概ねFindと同じ動作をします。

 Mookさんへ

 > 逆方向の検索は、Find に
 >SearchDirection:=xlPrevious
 >を追加するだけです。

 確かにオプションの設定はこれだけですが、
 セル範囲から、Findメソッドを使って、複数の検索をする場合、
 最初に見つかったセルを覚えておいて、次にそのセルが見つかったら検索終了
 というロジックをコードにしなければなりません。
 普段Findを使わない私には、これが面倒で・・・。

 メインプロシジャーでは、Dir関数のような運用を

 sub test()
    dim flnm as variant
    dim path as string
    path="d:\xxxx\*.*"
    flnm=dir(path)
    do until flnm=""
       msgbox flnm
       flnm=dir
    loop
 end sub

 Findメソッドでも行いたいと思っています。

 Sub test()
    Dim 検索値 As Variant
    検索値 = 1
    Dim rng As Range
    Set rng = get_findcell(検索値, Range("a1:a100"), , , , , xlPrevious)
    Do Until rng Is Nothing
       rng.Select
       MsgBox "ok"
       Set rng = get_findcell
    Loop
 End Sub

 >パフォーマンスに関してですが、EXCEL が用意している関数は、
 >同等のものをコードで書いたものに比べても高速である場合も
 >あるようです。

 これに関しては私も以前、別掲示板で何人かの方に御協力いただいて、

http://www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=16648;id=excel

 こんなことをしたことがありました。
 Findは、フリガナまで検索するもんね(良い場合と悪い場合があります)
 上位バージョンでは、これも選択できるようになっているのだろうか?

 ichinose

    


ichinose殿、Mook殿
 色々とアドバイス有難う御座います。
 ウ〜ム、
 話が自分レベルには難しくなってきました… φ(*_*)
 何処までを「VBA」「ワークシート関数」で処理するか、
 柔軟に考えるようにしてみます。

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.