ListBoxを操作するクラスモジュール ⑦ 正規表現によるマッチング
ListBoxを操作するクラスモジュールを、私なりに作成中。
前回は、リストボックスの列数および列幅を自動調整することに挑戦した。
infoment.hatenablog.com
今日も、前回の続きから。
前々回に、検索値を含む行だけでリストボックスを更新してみた。
こうなると、いつものように正規表現版も欲しくなる。
ということで、追加してみた。
クラスモジュール(ListBoxControl)
' リストボックス内にある値を正規表現で探し、マッチする値が ' 含まれる行について、そのインデックスを配列で返す。 Public Function RegExpAll(raPattern As Variant, _ Optional target_column As Long = -1, _ Optional raIgnoreCase As Boolean = False) As Variant ' インデックス格納用辞書。 ' 後ほどキー情報をまとめて配列として渡せること、要素数に応じた ' 拡張が自動で行われることを理由に、辞書を用いている。 Dim Dict As Object Set Dict = CreateObject("Scripting.Dictionary") Dim myReg As Object Set myReg = CreateObject("VBScript.RegExp") ' 正規表現のパターン。 myReg.Pattern = raPattern ' 大文字小文字の区別。 myReg.IgnoreCase = raIgnoreCase Dim Temp As String For j = 0 To UBound(LatestListArray, 2) ' 列数指定が-1、つまり未指定であるならば、リストボックス全体を ' 検索対象とする。 If target_column = -1 Or target_column = j Then For i = 0 To UBound(LatestListArray) Temp = LatestListArray(i, j) ' 部分一致対応のため、Like演算子で比較。 ' 辞書のItem情報は使用しないため不問。今回は一致したという ' 意味を込めて「True」としている(実際は、何でもよい)。 On Error GoTo er: If myReg.Test(Temp) Then Dict(i) = True End If Next End If Next ' キー情報(つまりインデックス情報)を戻り値とする。 RegExpAll = Dict.keys ' 戻り値としての配列を昇順ソート。 RegExpAll = SortArray(RegExpAll) Exit Function er: RegExpAll = Array() End Function ' リストボックス内にある検索値が含まれる行について、 ' その全てを選択する。 Public Sub RegExpAndSelectAll(raPattern As Variant, _ Optional target_column As Long = -1, _ Optional raIgnoreCase As Boolean = False) ' 検索値を含まない行が選択されたままとならないよう、全行の選択状態を ' 解除しておく。 Call UnselectAll ' 検索値を含む行のインデックスを配列で受け取る。 Dim arr As Variant arr = RegExpAll(raPattern, target_column, raIgnoreCase) TargetListBox.MultiSelect = fmMultiSelectMulti ' 受け取ったインデックスの行をすべて選択する。 Dim LoopIndex As Variant For Each LoopIndex In arr TargetListBox.Selected(LoopIndex) = True Next End Sub ' リストボックス内にある検索値が含まれる行のみで ' リストボックスを更新する。 Public Sub RegExpAndUpdateList(raPattern As Variant, _ Optional target_column As Long = -1, _ Optional raIgnoreCase As Boolean = False) ' 検索値を含む行のインデックスを配列で受け取る。 Dim arr As Variant arr = RegExpAll(raPattern, target_column, raIgnoreCase) If UBound(arr) = -1 Then Exit Sub ' 検索値のみのリスト仮受け。 Dim Temp() As Variant ReDim Temp(UBound(arr), UBound(SourceListArray, 2)) Dim LoopIndex As Variant i = 0 For Each LoopIndex In arr For j = 0 To UBound(Temp, 2) Temp(i, j) = LatestListArray(LoopIndex, j) Next i = i + 1 Next LatestListArray = Temp Call UpdateList(LatestListArray) End Sub
また、絞り込み結果を逐次リセットできるよう、以下も追加した。
Public Sub ResetList() ' 元の配列でリストを初期化する。 UpdateList SourceListArray End Sub
ユーザーフォーム
使い方としては、例えばこんな感じだ。前回の横長リストボックスの下に、
テキストボックスを配置する。
このテキストボックスの値が変わるたびに、以下を実行してみる。
Private Sub TextBox1_Change() Lbc.ResetList If TextBox1.Value <> vbNullString Then Lbc.RegExpAndUpdateList TextBox1.Value End If End Sub
すると、テキストボックスに入力した値で、即時絞り込みが可能となる。
例えば、「大」から始まって「子」または「美」で終わる名前の文字数が
5文字の方を抽出してみよう。
このように、なんちゃって個人情報5000人分の名簿ぐらいであれば、
処理待ち時間のストレスなく絞り込みが出来そうだ。
もう少し続きます。
参考まで。