今回のテーマ
前回と同じテーマです。
一つのセルに、3桁の数字が3つあります。これらは、半角スペースで区切られています。この数字について、真ん中のグループの和を求めてみましょう。
ユーザー定義関数内で正規表現を活用
前回までのユーザー定義関数は、規則正しく入力されている場合にのみ有効でした。それ以前に取り扱った正規表現では、様々な「例外」に対応していました。そこで今回は、両者の良いとこ取りをしてみましょう。
Function Calc2(r As Range, myIndex As Long) As Long Dim str As String Dim myReg As New RegExp Dim matchCase As MatchCollection ' 正規表現のパターン定義 myReg.Pattern = "(\d+)\D?" ' 正規表現の検索条件 ※ひとつ見つけても検索を止めない myReg.Global = True ' 半角と全角が混在するため、一旦全て半角化 str = StrConv(r.Value, vbNarrow) ' パターンにマッチする場合、True が返る If myReg.test(str) = True Then ' パターンマッチした結果を、マッチコレクションに格納する Set matchCase = myReg.Execute(str) ' 指定したグループの数を、Calc2に返す。 If matchCase.Count >= myIndex Then Calc2 = matchCase(myIndex).SubMatches(0) Else Calc2 = 0 End If End If End Function
前回の正規表現を用いたマクロから、数値を抜き出す部分だけを関数にしています。このように、特定の機能でプロシージャを分割するのは、とても有効な手段です。なぜなら機能ごとに分割しておけば、レゴブロックのように組み合わせを変えるだけで、別のマクロを容易に作成できるようになるからです。
それでは、Function 部分は繰り返しになりますが、正規表現のみだったプロシージャを二つに分割してみましょう。
Sub myCalc() Dim i As Long Dim iMax As Long ' 最終行番号の取得 iMax = Cells(Rows.Count, 1).End(xlUp).Row - 1 ' 合計セルの初期化 Cells(iMax + 1, 2) = 0 ' 各行の値抽出と足し算 For i = 2 To iMax Cells(iMax + 1, 2) = Cells(iMax + 1, 2) + Calc2(Cells(i, 1), 1) Next End Sub Function Calc2(r As Range, myIndex As Long) As Long Dim str As String Dim myReg As New RegExp Dim matchCase As MatchCollection ' 正規表現のパターン定義 myReg.Pattern = "(\d+)\D?" ' 正規表現の検索条件 ※ひとつ見つけても検索を止めない myReg.Global = True ' 半角と全角が混在するため、一旦全て半角化 str = StrConv(r.Value, vbNarrow) ' パターンにマッチする場合、True が返る If myReg.test(str) = True Then ' パターンマッチした結果を、マッチコレクションに格納する Set matchCase = myReg.Execute(str) ' 指定したグループの数を、Calc2に返す。 If matchCase.Count >= myIndex Then Calc2 = matchCase(myIndex).SubMatches(0) Else Calc2 = 0 End If End If End Function
メイン部分である Calc が、非常にスッキリした形になりました。
おわりに
今回の方法に対する評価(私見)は、以下の通りです。
メリット :
- 特定の機能をユーザー定義関数として分割することで、メイン部分が短く分かり易くなった。
- 特定の機能を、他のマクロで流用することが出来るようになった。
デメリット:
- 他のブックにコピーした場合、コピー先に同じユーザー定義関数がなければエラーになる。
長らく扱ってきたこのテーマも、今回でいったん終了します。
次回からは、別のテーマに取り組んでみます。
(おわり)