ワンランク上のVBAを書いてみた その4

# ワンランVBAシリーズ　その４ 【正規表現】

今回は、正規表現を手軽に扱えるようにしてみました。
正規表現を各までに、手間がかかるので、その手間を省いてサクッと実行できるようなサブプロシージャ化してみました。

また、合わせてPython用も用意しました。
---

# TransformString (VBA / Python) ドキュメント

## 目次
1. [概要](#概要)  
2. [VBA版コード](#vba版コード)  
3. [Python版コード](#python版コード)  
4. [機能と使い方](#機能と使い方)  
5. [想定利用状況](#想定利用状況)

---

## 概要
文字列に対して **正規表現** を用いたパターン判定・置換を行う機能です。  
VB(A) や Python で実装されているため、それぞれの環境で呼び出して利用できます。

- **VBA版**: `TransformString` 関数  
- **Python版**: `transform_string` 関数

VB(A) 版では VBScript の `RegExp` オブジェクトを使い、Python 版では `re` モジュールを使っています。  
いずれも以下の仕様に基づきます。  

1. 指定した `pattern`（正規表現）にマッチするかを確認  
2. マッチした場合にのみ `replacePattern` で最初の箇所を置換する  
3. マッチしない、またはエラー時には元の文字列を返す  

> **IgnoreCase** (大文字小文字の区別なし)  
> **Global=False** (最初のマッチのみ置換)

---

## VBA版コード
こちらを稼働させるには、参照設定から「Microsoft VBScript Regular Expressions 5.5」をセットしている必要があります。

```vb
' ===============================================
' TransformString (VBA / VBScript)
' ===============================================
' Ex:) TransformString("2024年12月02日 0:00", "^(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}:\d{2})$", "$1/$2/$3 $4")

Function TransformString(inputStr As String, pattern As String, replacePattern As String) As String
    On Error GoTo ErrorHandler
    
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    With regex
        .pattern = pattern
        .IgnoreCase = True    ' 大文字小文字の区別をしない
        .Global = False       ' 最初のマッチのみ置換
    End With
    
    If regex.Test(inputStr) Then
        TransformString = regex.Replace(inputStr, replacePattern)
    Else
        TransformString = inputStr
    End If
    
    Exit Function

ErrorHandler:
    ' エラーが発生した場合は元の文字列を返す
    TransformString = inputStr
    ' 必要に応じてログ出力やメッセージ表示を行う
    ' MsgBox "エラーが発生しました: " & Err.Description, vbExclamation
End Function
```

- `pattern`: 置換判定に用いる正規表現（例： `^(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}:\d{2})$` ）  
- `replacePattern`: 置換先の文字列パターン（例： `$1/$2/$3 $4` ）  

---

## Python版コード

```python
import re

def transform_string(input_str: str, pattern: str, replace_pattern: str) -> str:
    """
    VBScriptのTransformStringと同等の処理をPythonで実装した例。

    - pattern:        正規表現パターン (VB(A)での regex.pattern に対応)
    - replace_pattern:置換パターン     (VB(A)での regex.Replace に対応)
    - IgnoreCase=True :大文字・小文字の区別をしない
    - Global=False   :最初にマッチした1ヶ所のみ置換
    """
    try:
        # 大文字・小文字を区別しないオプションを付与
        compiled_pattern = re.compile(pattern, re.IGNORECASE)
        
        # マッチテスト (VB(A)での regex.Test(inputStr) 相当)
        if compiled_pattern.search(input_str):
            # 最初にマッチした1つのみを置換
            return compiled_pattern.sub(replace_pattern, input_str, count=1)
        else:
            # マッチしない場合は元の文字列を返す
            return input_str
    except Exception:
        # エラー発生時は元の文字列を返す
        return input_str


# 動作例
if __name__ == "__main__":
    test_str = "2024年12月02日 0:00"
    pattern = r"^(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}:\d{2})$"
    replace_pattern = r"\1/\2/\3 \4"

    result = transform_string(test_str, pattern, replace_pattern)
    print(result)  # 期待出力: "2024/12/2 0:00"
```

---

## 機能と使い方
### 1. マッチング処理
- いずれの実装でも、正規表現 `pattern` を使って文字列 `inputStr` がマッチするか確認。  
- マッチがなければ何もせず、元の文字列を返す。

### 2. 置換処理
- マッチした場合のみ `replacePattern` で**最初の1回**だけ置換を行う。  
  - 例えば `(\d+)` に捕捉された文字列を `$1` (VBA) や `\1` (Python) で参照しながら置換できる。

### 3. エラー処理
- VB(A) 版では `On Error GoTo ErrorHandler` を使い、何らかの例外が発生した場合、元の文字列を返す。  
- Python 版では `try-except` ブロックで同様の処理を行い、元の文字列を返す。

### 4. 大文字・小文字の区別
- VB(A) 版: `.IgnoreCase = True`  
- Python 版: `re.compile(pattern, re.IGNORECASE)`  

### 5. 最初のマッチのみ置換
- VB(A) 版: `.Global = False`  
- Python 版: `sub(..., count=1)`  

---

## 想定利用状況
- **日付フォーマット変換**  
  例: `yyyy年MM月dd日 HH:mm` → `yyyy/MM/dd HH:mm`  
- **電話番号や郵便番号など特定形式への書式統一**  
  例: `090-1234-5678` → `TEL:090-1234-5678`  
- **ログ解析やテキスト処理**  
  例: `[INFO] Something...` → `INFO: Something...`  
- **Webフォーム入力のフォーマットチェック**  
  例: カタカナの全角/半角の統一など  

いずれのケースでも、**パターンにマッチした最初の1回だけ置換をしたい**、  
または**正規表現で何らかの解析をしたい**という場合に活用できます。

---