VBAで正規表現を利用するには
VBAでも正規表現が利用できます。正規表現を利用するにはVBScriptのRegExpクラスを利用します。RegExpはRegular Expressionの略です。
RegExpクラスを使うには使い方に順序があり、事前にインスタンスの生成(New RegExpもしくはCreateObject関数)が必要になります。そしてインスタンス生成後にRegExpクラスの各種プロパティへの設定を行ったあとに正規表現での文字列処理の実行を行います。
このあたりについては後述しています。
なお、VBAで扱える正規表現のメタ文字についての詳細は「VBAで扱える正規表現の種類」をご参照ください。
事前に参照設定を行う
RegExpクラスを利用するには2通りの方法があります。
- CreateObject関数でRegExpクラスのインスタンスを生成する方法
- 参照設定する方法
どちらの方法でもいいのですが、参照設定をした方が便利です。正規表現の参照設定の方法は次の通りです。
- VBAの画面でツールメニュー→参照設定 を選択します。
- 参照設定ダイアログで「Microsoft VBScript Regular Expressions 5.5」にチェックを付けます。
- OKボタンを押して閉じます。
これで設定は終わりです。
RegExpクラスの変数宣言の書き方
RegExpクラスの変数宣言とインスタンスの生成の書き方について、参照設定をした場合とCreateObject関数を使った場合のそれぞれの書き方を説明します。
参照設定を使った場合の書き方
1行で書く方法と2行に分けて書く方法があります。厳密な意味で安全なのは2行に分けて書く方法です。
1 2 |
Dim reg As RegExp Set reg = New RegExp |
ただ、1行で書いても構いません。私は1行で書くことが圧倒的に多いです。この理由については「VBAでクラス変数の宣言とNewを1行で書いてよいか」をご参照ください。
1 |
Dim reg As New RegExp |
CreateObject関数を使った場合の書き方
1 2 |
Dim reg As Object Set reg = CreateObject("VBScript.RegExp") |
RegExpクラスのプロパティとメソッド
RegExpクラスには3つのプロパティと3つのメソッドがあります。
プロパティ
Global | 指定文字列の中に事前に設定された正規表現の検索パターンがあるか検索する際に、指定文字列の左端から1度だけ検索(False)するか、1度見つかったあともその右側の残りの文字列に対しても検索(True)するかを指定します。既定値はFalseです。
Executeメソッドの結果とReplaceメソッドの結果に影響します。Testメソッドには影響しません。 Executeメソッドの場合は検索一致した最初の部分だけか、検索一致した全ての部分のどちらをMatchesCollectionオブジェクトに格納するかに影響します。Replaceメソッドの場合は最初に見つかった部分だけを置換するか、指定文字列の中で見つかった置換対象部分全てを置換するかの違いに影響します。 <構文> |
IgnoreCase | Patternプロパティで指定した検索パターンで、大文字と小文字を区別するかどうかを指定します。区別しない場合はTrueを指定します。区別する場合はFalseを指定します。省略時はFalse扱いになります。
<構文> |
Pattern | Executeメソッド、Replaceメソッド、Testメソッドの引数文字列に対する正規表現の検索パターンを指定します。数字1文字を検索する場合は「”[0-9]”」、英単語を検索する場合は「”[a-zA-Z]+”」のように正規表現の文字列を指定します。事前に設定済みの検索パターンを取得することも可能です。
<構文> |
メソッド
Execute | 事前に設定された正規表現での検索パターンが、指定された文字列に含まれるか検索し、検索結果をMatchesCollectionオブジェクトで返します。検索で見つからなかった場合は空のMatchesCollecionオブジェクトを返します。
<構文>
|
||||||
Replace | 指定された文字列の中から、事前に設定された正規表現での検索パターンで見つかった部分を、置換後文字列で置換します。
<構文>
|
||||||
Test | 事前に設定された正規表現での検索パターンが、指定された文字列に含まれるかどうかをBoolean型で返します。一致する文字列があればTrueを返し、一致する文字列がなければFalseを返します。
<構文>
|
RegExpクラスの使い方
RegExpクラスを使う際には以下の流れを守る必要があります。
- 検索範囲(Globalプロパティ)、大文字小文字の扱い(IgnoreCaseプロパティ)、検索文字列(Patternプロパティ)を設定します。
- そのあとに検索(Executeメソッド)や置換(Replaceメソッド)や存在チェック(Testメソッド)を実行します。
- 検索結果を判定します。(MatchCollectionコレクション、Matchオブジェクト、SubMatchesコレクション)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
Sub RegExpTest() Dim s '// 検索対象文字列 Dim reg As New RegExp '// 正規表現クラスオブジェクト Dim oMatches As MatchCollection '// RegExp.Execute結果 Dim oMatch As Match '// 検索結果オブジェクト Dim i '// ループカウンタ Dim iCount '// 検索一致件数 Dim iFirstIndex '// 最初の検索一致位置 Dim iLength '// 検索一致文字列の長さ Dim sValue '// 検索一致文字列 Dim oSubMatches As SubMatches '// 検索結果の部分一致コレクション Dim iSub '// サブ表現のループカウンタ Dim iSubCount '// サブ表現の検索一致件数 '// 検索対象文字列 s = "abcd1234efgh5678ijkl9012" '// 検索条件設定 reg.Global = True '// 検索範囲(True:文字列の最後まで検索、False:最初の一致まで検索) reg.IgnoreCase = True '// 大文字小文字の区別(True:区別しない、False:区別する) reg.Pattern = "([a-z]+)(\d+)" '// 検索パターン(ここでは連続する数字を検索条件に設定) '// 検索実行 Set oMatches = reg.Execute(s) '// 検索一致件数を取得 iCount = oMatches.Count '// 検索一致件数だけループ For i = 0 To iCount - 1 '// コレクションの現ループオブジェクトを取得 Set oMatch = oMatches.Item(i) '// 最初の検索一致位置 iFirstIndex = oMatch.FirstIndex '// 検索一致文字列の長さ iLength = oMatch.Length '// 検索一致文字列 sValue = oMatch.Value Debug.Print "最初検索一致位置:" & iFirstIndex & " 長さ:" & iLength & " 文字列:" & sValue '// 検索一致 Set oSubMatches = oMatch.SubMatches '// サブ表現(丸括弧で囲われている検索条件)されている数を取得 iSubCount = oSubMatches.Count '// サブ表現の数だけループ For iSub = 0 To iSubCount - 1 Debug.Print "サブ表現一致文字列:" & oSubMatches.Item(iSub) Next Next End Sub |
実行結果は以下の通りです。
1 2 3 4 5 6 7 8 9 |
最初検索一致位置:0 長さ:8 文字列:abcd1234 サブ表現一致文字列:abcd サブ表現一致文字列:1234 最初検索一致位置:8 長さ:8 文字列:efgh5678 サブ表現一致文字列:efgh サブ表現一致文字列:5678 最初検索一致位置:16 長さ:8 文字列:ijkl9012 サブ表現一致文字列:ijkl サブ表現一致文字列:9012 |
注意点:MatchesではなくMatchCollectionが正しい
以下のMicrosoftのヘルプにExecuteメソッドについて戻り値はMatchesコレクション、と書いてありますが、正しくは MatchCollectionコレクションです。
https://msdn.microsoft.com/ja-jp/library/cc392389.aspx
いろんなサイトでもMicrosoftのヘルプに合わせているのか「Matchesコレクション」と書いてあることが多いようです。
CreateObjectを利用していて気が付いていないのかもしれません。