Excelが大好きだ!

Excel大好き経理マンがExcelの事を書き綴っていきます。


スポンサードリンク

正規表現検索が出来るユーザー定義関数を作った

エクセルの神髄さんのExcelクイズをきっかけに発生したやりとりをヒントに、正規表現検索が出来るユーザー定義関数を作成してみました。



正規表現とは

正規表現(せいきひょうげん、: regular expression)は、文字列の集合を一つの文字列で表現する方法の一つである。

正規表現 - Wikipedia

わかりにくいですが、特殊な検索文字列を使用して、普通の検索では抽出することができない検索を実行できる、という認識で良いと思います。(私の認識がそれくらいです。


ユーザー定義関数コード

下記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関数に渡す
  • 上記結果の配列を引数に応じて加工


正規表現

正規表現のパターンについては当記事では触れません。

例えば下記のサイト等ご参考ください。

基本的な正規表現一覧 | murashun.jp


まとめ

正規表現は使うことが出来ると柔軟に文章から文字列を抽出することが出来ます。

関数の設計にあたっては、twitterのフォロワーさんから頂いたアイデアを取り入れさせて頂きました。 ありがとうございます。