エクセルの神髄さんのExcelクイズをきっかけに発生したやりとりをヒントに、正規表現検索が出来るユーザー定義関数を作成してみました。
「エクセル頭の体操」実務編
— エクセルの神髄 (@yamaoka_ss) 2022年6月18日
コメントから特定形式「(yyyy年mm月)」の年月だけを取り出してください。 pic.twitter.com/aeBu6RyVSN
正規表現とは
正規表現(せいきひょうげん、英: regular expression)は、文字列の集合を一つの文字列で表現する方法の一つである。
わかりにくいですが、特殊な検索文字列を使用して、普通の検索では抽出することができない検索を実行できる、という認識で良いと思います。(私の認識がそれくらいです。
ユーザー定義関数コード
下記2つのコードを標準モジュールにコピペすればワークシート上で『正規表現検索』関数が使用できるようになります。
スピル非対応のExcelの場合は検索結果が配列で返ってきていますので、index関数を使用すれば、2つ目以降の値を表示することが出来ます。
Function 正規表現検索(検索対象 As Variant, 検索正規表現 As String, _ Optional 添字 As Long = 0, _ Optional 返却数 As Long = 0) As Variant Dim tmp As Variant tmp = RegSearch(検索対象, 検索正規表現, False) '--正規表現検索で受け取った結果配列を処理 '--第3引数処理 Dim ans As Variant If 添字 = 0 Then ans = tmp ElseIf 添字 < 0 Then ans = tmp(UBound(tmp) + 添字 + 1) Else ans = tmp(添字) End If '--第4引数処理 If 添字 = 0 And 返却数 <> 0 Then Dim var As Variant ReDim ans(1 To WorksheetFunction.Min(UBound(tmp), Abs(返却数))) Dim i As Long: i = 1 For i = 1 To UBound(ans) If 返却数 > 0 Then ans(i) = tmp(i) Else ans(i) = tmp(UBound(tmp) - i + 1) End If Next End If 正規表現検索 = ans End Function
Private Function RegSearch(調査対象文字列 As Variant, _ 正規表現文字列 As String, _ 大文字小文字区別判定 As Boolean) As Variant Dim myReg As Object Set myReg = CreateObject("VBScript.RegExp") '--Microsoft VBScript Reglar Expressions5.5を参照設定した場合 ' Dim myReg As RegExp: Set myReg = New RegExp Dim vvSearchString As String: vvSearchString = 調査対象文字列 myReg.Pattern = 正規表現文字列 myReg.Global = True '複数マッチするかどうか。Trueで複数対応 myReg.IgnoreCase = Not 大文字小文字区別判定 'Trueで区別しない。 Dim var As Variant If myReg.test(vvSearchString) Then Dim Matches As Object Set Matches = myReg.Execute(vvSearchString) Dim vvMatch As Object ReDim var(1 To Matches.Count) Dim i As Long: i = 1 For Each vvMatch In Matches var(i) = vvMatch i = i + 1 Next Else var = Array() End If RegSearch = var Set myReg = Nothing End Function
2つの関数は以下の役割を担っています。
関数名 | 役割 |
---|---|
正規表現検索 | ワークシート上から実際に呼び出す関数。 RegSearchの返り値である配列を処理。 |
RegSearch | 正規表現検索関数から呼び出される関数。 実際に正規表現検索を行う。 検索結果を配列として返す。 |
正規表現検索 関数
引数 | 機能 |
---|---|
検索対象 | 正規表現で検索する文字列を指定 |
検索正規表現 | 正規表現を設定 |
添字 | 正規表現に一致した検索結果配列の内、何番目の値を返すか指定。 0の場合は全件。マイナスの場合は配列の後ろから数えた位置を返す |
返却数 | 正規表現に一致した検索結果配列の内、先頭からいくつの答えを返すか指定。マイナスの場合は配列の後ろから数えた答えを返す。 第3引数「添字」が0の場合のみ動作する。 |
RegSearch関数
引数 | 機能 |
---|---|
調査対象文字列 | 正規表現検索 関数の引数「検索対象」を受け取る |
正規表現文字列 | 正規表現検索 関数の引数「検索正規表現」を受け取る |
大文字小文字区別判定 | 正規表現検索の際に大文字・小文字区別するかどうか。 TRUEで区別する。 |
RegExp
使用方法
VBAで正規表現を使うにはRegExpオブジェクトを使用します。
RegExpオブジェクトを使用するには2つの方法があります。
- 事前バインディング
ツール → 参照設定 からMicrosoft VBScript Regular Expressions 5.5にチェックを入れます。
チェック後コード内で下記の宣言を行います。
Dim 変数 As RegExp Set 変数 = New RegExp
- 実行時バインディング
参照設定は行わず、下記の宣言を行います。
Dim 変数 As Object Set 変数 = CreateObject("VBScript.RegExp")
メソッド・プロパティ
今回のコードの中では下記のメソッド・プロパティを使用しています。
プロパティ名 | 機能 |
---|---|
Pattern | 正規表現を設定します |
Global | boolean型 正規表現に一致した文字列の内、最初の1つだけを返すか、一致した文字列をすべて返すか。 TRUE:複数検索 FALSE:最初の1つだけ(既定値) |
IgnoreCase | boolean型 検索時に大文字・小文字を区別するかどうか。 TRUE:区別しない FALSE:区別する(既定値) |
メソッド名 | 機能 |
---|---|
Test (検索文字列) | Patternプロパティで設定した正規表現に一致する文字列が引数「検索文字列」内にあるかチェックする。 一致する文字列がある場合はTRUEを返す。 無い場合はFALSEを返す。 |
Execute(検索文字列) | 引数「検索文字列」内をPatternプロパティで設定した正規表現で検索します。 検索結果をMatchesコレクションとして返します。 |
処理の流れ
RegSearch関数内では以下の処理を行っています。
正規表現検索 関数では以下の処理を行っています。
- 検索対象文字列、正規表現の設定
- 上記をRegSearch関数に渡す
- 上記結果の配列を引数に応じて加工
正規表現
正規表現のパターンについては当記事では触れません。
例えば下記のサイト等ご参考ください。
まとめ
正規表現は使うことが出来ると柔軟に文章から文字列を抽出することが出来ます。
関数の設計にあたっては、twitterのフォロワーさんから頂いたアイデアを取り入れさせて頂きました。 ありがとうございます。