【実務・中級編】【中級者向け】表内のテキストを正規表現で検索し、特定のパターンに合致するセルを強調する – Word VBA解析バイブル

スポンサーリンク
スポンサーリンク

Word VBAの限界を突破せよ:VBScript.RegExpによる表内パターン検索の極致

業務自動化の現場において、Wordの標準機能である「検索と置換(Find)」に頼り切っている設計者は、いずれ必ず壁にぶち当たる。

標準のワイルドカード検索は、一見便利に見えるが、極めて限定的な記法しか許容しない。例えば、「特定のアルファベット2文字+ハイフン+数字4桁」といった、実務で頻出する「型番」や、複雑な形式の「日付」を正確に、かつ柔軟に抽出するには、標準機能では力不足だ。

真にプロフェッショナルなツールを構築するなら、VBScript.RegExp(正規表現エンジン)をWord VBAのプロセスに組み込み、セル内のテキストを精密にスキャンするアーキテクチャを採用すべきである。

本稿では、単なる「動くコード」の提供ではない。大規模な文書でも破綻せず、保守性を担保した「プロダクション・グレード」の設計思想を伝授する。

1. なぜ標準の `Find` では不十分なのか

Wordの `Find` オブジェクトが持つワイルドカード機能は、あくまで「文書全体」を対象とした簡易的なものである。

  • パターンの柔軟性の欠如: 「数字が3桁以上続くが、特定の記号が含まれる場合は除外する」といった、条件付きのパターンマッチングが極めて困難。
  • セル単位の制御が困難: 表の特定の列、あるいは特定のセルの内容に対してのみ、高度なロジックを適用しようとすると、コードがスパゲッティ化する。
  • 検索結果の事後処理: マッチした箇所に対して「セルの背景色を変える」「特定の書式を適用する」といった操作を、正規表現の「グループ化(Capturing Groups)」と連動させるのが難しい。

これらを解決するのが、外部エンジンである `VBScript.RegExp` の活用だ。

2. 設計における致命的な落とし穴:Wordセルの「隠れた文字」

実装に入る前に、中級者が必ず陥る罠について警告しておく。

Wordの `Table.Cell.Range.Text` プロパティから取得できる文字列には、末尾に必ず `Chr(13) & Chr(7)` (キャリッジリターンとベル文字)が含まれている。これを考慮せずに正規表現を適用すると、パターンの末尾一致(`$`)が絶対にヒットしないという、不可解なバグに直面することになる。

堅牢なコードを書くなら、この末尾文字を確実に削ぎ落とす処理を共通ロジックとして組み込むのが鉄則だ。

3. プロダクション・グレードのコード実装

以下に、文書内のすべての表を走査し、正規表現に合致するパターンを持つセルを特定して、背景色を強調する実装例を示す。ここでは、保守性を考慮し、レイトバインディング(遅延結合)を採用している。これにより、参照設定の手間を省き、配布時のトラブルを最小限に抑える。

Option Explicit

''' <summary>
''' 文書内の全テーブルを走査し、正規表現パターンに合致するセルを強調する。
''' </summary>
''' <param name="pattern">検索する正規表現パターン</param>
''' <param name="highlightColor">強調するセルの背景色</param>
Public Sub HighlightCellsByRegex(ByVal pattern As String, Optional ByVal highlightColor As Long = vbYellow)
    Dim doc As Document
    Dim tbl As Table
    Dim cl As Cell
    Dim regEx As Object ' VBScript.RegExp
    Dim cellText As String
    Dim cleanText As String
    Dim matchCount As Long
    
    Set doc = ActiveDocument
    matchCount = 0

    ' --- 1. 正規表現エンジンの初期化 ---
    ' レイトバインディングにより、参照設定なしで動作させる
    On Error Resume Next
    Set regEx = CreateObject("VBScript.RegExp")
    If regEx Is Nothing Then
        MsgBox "VBScript.RegExpの生成に失敗しました。環境を確認してください。", vbCritical
        Exit Sub
    End If
    On Error GoTo 0

    With regEx
        .Pattern = pattern
        .Global = True          ' 文書内の全一致を対象とする
        .IgnoreCase = True      ' 大文字小文字を区別しない(実務上の柔軟性)
    End With

    ' --- 2. パフォーマンス最適化 ---
    ' 画面更新を停止し、描画コストを削減する
    Application.ScreenUpdating = False

    On Error GoTo ErrorHandler

    ' --- 3. テーブル走査ループ ---
    ' 全テーブル、全セルを走査する O(N*M) の計算量
    For Each tbl In doc.Tables
        For Each cl In tbl.Range.Cells
            
            ' セル内のテキストを取得
            cellText = cl.Range.Text
            
            ' 【重要】Word特有の末尾文字 (Chr(13) & Chr(7)) を除去
            ' これを行わないと、正規表現の末尾一致判定が失敗する
            If Len(cellText) > 2 Then
                cleanText = Left(cellText, Len(cellText) - 2)
            Else
                cleanText = ""
            End If

            ' --- 4. 正規表現によるマッチング判定 ---
            If regEx.Test(cleanText) Then
                ' マッチした場合、セルの書式を変更
                ' セル全体を対象にするため、Rangeオブジェクトを操作
                cl.Shading.BackgroundPatternColor = highlightColor
                matchCount = matchCount + 1
            End If
            
        Next cl
    Next tbl

    ' --- 5. 後処理 ---
    Application.ScreenUpdating = True
    MsgBox "処理が完了しました。" & vbCrLf & _
           "強調したセル数: " & matchCount, vbInformation, "完了"

    Set regEx = Nothing
    Exit Sub

ErrorHandler:
    Application.ScreenUpdating = True
    MsgBox "予期せぬエラーが発生しました。" & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "内容: " & Err.Description, vbCritical, "システムエラー"
    Set regEx = Nothing
End Sub

''' <summary>
''' テスト実行用メインルーチン
''' </summary>
Public Sub Test_RegexHighlighting()
    ' 例1: 型番パターン (例: AB-12345)
    ' パターン解説: [A-Z]{2} (英大文字2文字) + "-" + \d{4,5} (数字4〜5桁)
    Call HighlightCellsByRegex("[A-Z]{2}-\d{4,5}", vbCyan)
    
    ' 例2: 日付パターン (例: 2023/10/25 または 2023-10-25)
    ' Call HighlightCellsByRegex("\d{4}[/-]\d{2}[/-]\d{2}", vbGreen)
End Sub

4. アーキテクトの視点:なぜこの設計なのか

このコードが「ただのコピペ用コード」と一線を画す理由は、以下の3点に集約される。

① エラーハンドリングの階層化

`On Error GoTo ErrorHandler` を用いて、ループの途中でエラーが発生しても、必ず `Application.ScreenUpdating = True` を実行して画面更新を元に戻すように設計している。これを怠ると、エラー発生後にWordの描画が止まり、ユーザーに「フリーズした」という誤解を与え、信頼を失う。

② 計算量とパフォーマンスの意識

`Application.ScreenUpdating = False` は、大規模な表を扱う際の必須テクニックだ。Wordの描画エンジンは、セル一つ一つの背景色が変わるたびに画面を再描画しようとする。これを抑制することで、実行速度を数倍から数十倍に引き上げることができる。

③ 疎結合な設計

`HighlightCellsByRegex` 関数は、検索パターンと色を引数として受け取る。これにより、「型番を探したい時」「日付を探したい時」に、ロジックを書き換えることなく、呼び出し側(`Test_RegexHighlighting`)のパラメータを変えるだけで対応できる。これが保守性の高いコードの定義である。

5. さらなる高みへ:データベース・外部連携への展開

実務では、この正規表現検索の結果を「単に色を塗る」だけで終わらせることはない。

  • Excel/SQLとの連携: マッチした値を抽出(`regEx.Execute`)し、それをExcelのマスターデータやSQLデータベースと照合させ、「在庫切れの型番」だけを赤く塗る、といった高度なロジックへ拡張せよ。
  • Early Bindingへの移行: もし、数万行に及ぶ膨大な表をミリ秒単位の速度で処理する必要があるなら、参照設定から `Microsoft VBScript Regular Expressions 5.5` を追加し、`Dim regEx As RegExp` として記述する「アーリーバインディング」に切り替えろ。実行時の型判定コストを削減できる。

まとめ

Word VBAにおける正規表現の活用は、単なる「検索の強化」ではない。それは、非構造化データ(自由記述のセル)を、構造化データとして制御下に置くための武器である。

エンジニアとして、単に「動く」ものを作るな。「壊れない」「速い」「拡張できる」ものを作れ。それが、プロフェッショナルへの唯一の道だ。

タイトルとURLをコピーしました