ちょっと生きづらさを抱えた人へ、気持ちを楽にするためのお手紙です。

【VBA】正規表現を簡単に使えるようにクラス化

Excel VBAで正規表現を使うとき、特にサブマッチを使うとき、
書かなければいけないことが多くて面倒なので、
簡単に使えるようにクラス化してみました。

ツール > 参照設定 > microsoft vbscript regular expressions
ExcelVBA参照設定_02

Option Explicit

Public Function iterator() As IIterator
    
End Function
Option Explicit

Public Function hasNext() As Boolean

End Function

Public Function nextItem() As Object

End Function
Option Explicit

Implements IAggregate

'ツール > 参照設定 > microsoft vbscript regular expressions
Private regEx As New RegExp
Private regMc As MatchCollection
Private regMatch As Match

'-------------------------------------------------------------------------------
' デストラクタ
'-------------------------------------------------------------------------------
Private Sub Class_Terminate()
    Set regEx = Nothing
    Set regMc = Nothing
    Set regMatch = Nothing
End Sub

'-------------------------------------------------------------------------------
' iterator
'-------------------------------------------------------------------------------
Public Function IAggregate_iterator() As IIterator
    Dim res As New RegExpIterator
    Call res.init(Me)
    Set IAggregate_iterator = res
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】プロパティ設定
' 【引    数】isGlobal[Boolean]    :True  文字列全体に検索が適用
'                                    False 最初の一致だけに検索が適用
'             isIgnoreCase[Boolean]:True  検索時に大文字と小文字を区別する
'                                    False 検索時に大文字と小文字を区別しない
' 【返 却 値】なし
' 【処理概要】RegExpオブジェクトのプロパティを設定。
'-------------------------------------------------------------------------------
Public Sub setProperties(ByVal isGlobal As Boolean, ByVal isIgnoreCase As Boolean)
    With regEx
        .Global = isGlobal
        .IgnoreCase = isIgnoreCase
    End With
End Sub

'-------------------------------------------------------------------------------
' 【処 理 名】検索
' 【引    数】target[String] :検索対象文字列
'           pattern[String]:検索する文字列(正規表現パターン)
' 【返 却 値】なし
' 【処理概要】指定された文字列を正規表現で検索
'-------------------------------------------------------------------------------
Public Sub execute(ByVal target As String, ByVal pattern As String)
    regEx.pattern = pattern
    Set regMc = regEx.execute(target)
End Sub

'-------------------------------------------------------------------------------
' 【処 理 名】パターン一致判定
' 【引    数】target[String] :検索対象文字列
'             pattern[String]:検索する文字列(正規表現パターン)
' 【返 却 値】なし
' 【処理概要】指定された文字列を正規表現で検索し、パターンに一致する文字列が
'             検索されたかどうかを示すブール (Boolean) 値を返却。
'-------------------------------------------------------------------------------
Public Function test(ByVal target As String, ByVal pattern As String) As Boolean
    regEx.pattern = pattern
    test = regEx.test(target)
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】置換
' 【引    数】target[String]:検索および置換の対象となるテキスト文字列
'             before[String]:検索する文字列(正規表現パターン)
'             after[String] :置換するテキスト文字列
' 【返 却 値】置換後文字列
' 【処理概要】正規表現による検索で見つかったテキストを置換します。
'-------------------------------------------------------------------------------
Public Function Replace(ByVal target As String, ByVal before As String, ByVal after As String) As String
    regEx.pattern = before
    Replace = regEx.Replace(target, after)
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】マッチ件数取得
' 【引    数】なし
' 【返 却 値】検索マッチ件数
' 【処理概要】executeメソッドで検索したマッチ件数を返却
'-------------------------------------------------------------------------------
Public Function getCount() As Long
    getCount = regMc.Count
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】マッチ文字列取得
' 【引    数】index[Long]:検索でマッチした結果のインデックス
' 【返 却 値】マッチ
' 【処理概要】executeメソッドで検索したマッチした該当indexのマッチを返却
'-------------------------------------------------------------------------------
Public Function getRegMatchAt(ByVal index As Long) As Object
    Set getRegMatchAt = regMc.Item(index)
End Function
Option Explicit

Implements IIterator

Private reg As New RegExpAggregate
Private index As Long

'-------------------------------------------------------------------------------
' 【処 理 名】次エレメント存在チェック
' 【引    数】なし
' 【返 却 値】ブール値
' 【処理概要】collectionに次のエレメントがあるのブール (Boolean) 値を返却。
'-------------------------------------------------------------------------------
Public Function IIterator_hasNext() As Boolean
    If index < reg.getCount Then
        IIterator_hasNext = True
    Else
        IIterator_hasNext = False
    End If
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】次エレメント取得
' 【引    数】なし
' 【返 却 値】エレメント
' 【処理概要】collectionのエレメントを返却。
'-------------------------------------------------------------------------------
Public Function IIterator_nextItem() As Object
    Set IIterator_nextItem = reg.getRegMatchAt(index)
    index = index + 1
End Function

'-------------------------------------------------------------------------------
' 【処 理 名】初期化
' 【引    数】RegExpAggregate[IAggregate] ConcreteAggregate
' 【返 却 値】なし
' 【処理概要】イテレータを初期化する
'-------------------------------------------------------------------------------
Public Sub init(ByVal RegExpAggregate As IAggregate)
    Set reg = RegExpAggregate
    index = 0
End Sub

 

こんな感じで使う

Option Explicit

Public Sub main()
    Dim sql As String
    Dim ptn As String
    Dim reg As New RegExpAggregate
    Dim it As New IIterator
    Dim regMatch As Match
    
    sql = "SELECT HOGE, FUGA FROM TBL_A;SELECT FUGA, HOGE FROM TBL_B;"
    ptn = "(SELECT)\s+(.*?)\s+FROM\s+(.*?);"
    
    Call reg.setProperties(True, True)
    
    If reg.test(sql, ptn) Then
        Debug.Print "True"
    Else
        Debug.Print "False"
    End If
    
    Call reg.execute(sql, ptn)
    Set it = reg.IAggregate_iterator
    Do While (it.hasNext)
        Set regMatch = it.nextItem
        Debug.Print regMatch.SubMatches(2)
        'サブマッチを使わない場合はregMatch.valueで値を取得できる
    Loop
    
    Call reg.Replace(sql, "TBL_A", "TBL_C")
End Sub

 

setProperties()を設定しなければ、regExpオブジェクトのデフォルトで検索します。

Regular Expression オブジェクトのプロパティ

Global 検索文字列全体についてのパターンとの一致を検索するか、最初の一致だけを検索するかを示すブール (Boolean) 値を設定します。 True 文字列全体に検索が適用
False 最初の一致だけに検索が適用
IgnoreCase  

パターン検索で大文字と小文字を区別するかどうかを示すブール (Boolean) 値を設定します。

 True  検索するときに大文字と小文字を区別する
 False  検索するときに大文字と小文字を区別しない
Pattern  検索される正規表現のパターンを設定します。値の取得も可能です。 正規表現のパターンの記述には、特別な文字およびエスケープ シーケンスが使用されます。

 

クラスのテキストファイルを固めといたので、良かったらどうぞー。

参考
micro soft|Developer Network RegExp オブジェクト

1 COMMENT

コメントを残す

メールアドレスが公開されることはありません。