2013年1月5日土曜日

[ExcelVBA] 正規表現


正規表現とは、文字列の集合を一つの文字列で表現する方法の一つである。正則表現とも呼ばれ、形式言語理論の分野では比較的こちらの訳語の方が使われる。まれに正規式と呼ばれることもある。


知らない人には、何のこと?って感じでしょうが
文字列操作をする上で欠かせない物の一つでしょうね。

例えば、以下の5つの文章が配列にはいっていたとしましょう。
こんな感じです。
Dim List(2) as string
    List(0) = "最初のテストは国語で、9:00~10:30"
    List(1) = "2番目のテストは算数で、10:30~12:00"
    List(2) = "3番目のテストは理科で、13:00~14:30"

と、なっていた時、各要素の中から時間を抜き出しなさい。
と言われたらどうします?
まさか、0:00~23:59の1440通り作ってそれぞれマッチするかテストします?
さすがに、それは無茶な話しですよねぇ 汗


日本語で時間を表現するのであれば…
1文字目がない時は、2文字目が0-9、3文字目はコロン、4文字目が0-5、5文字目が0-9
1文字目が1の時は、2文字目が0-9、3文字目はコロン、4文字目が0-5、5文字目が0-9
1文字目が2の時は、2文字目が0-3、3文字目はコロン、4文字目が0-5、5文字目が0-9
と表現できます。

これを正規表現で表現するなら
(1?\d|2[0-3]):[0-5]\d
これすみます。
少ない文字列で大量の文字パターンを表現することが
できるというのが正規表現の醍醐味でしょうね。


たとえば、アルファベット26文字は、[a-z]で表現できます。
数字0~9は、[0-9]だったり\dで表現できます。
数字10桁は、\d{10}で全通り表現できます。



そんなこんなで正規表現についていろいろメモ書きしていきます。
最初は、正規表現の必要がないものばかりですが、
理解しやすさを優先しての結果ですのでご了承願います。


■ExcelVBAで正規表現(お決まりのお話)

ExcelVBA単体では正規表現を利用することができません。
そこで、VBScriptの力を借りることになります。
一般的に、IE5以上が入っていればExcelVBAからでも利用可能です。
なんて話しがありますが昨今のPCなら全く問題ないでしょうねぇ。

では、正規表現を利用するにあたって…

Dim Reg As Object
Set Reg = CreateObject("VBScript.RegExp")

と書くことが正規表現を使う第一歩となります。
ここからは、コードを通して使い方になれてみましょう。


■マッチするかしないか判断する。

"abcde"の中に"bc"があるかないかだけを調べるコードです。

Sub SampleCode1()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")

    Reg.Pattern = "bc" '正規表現セット    
    If Reg.Test("abcde") Then Debug.Print "match!"  'マッチする
    Debug.Print "---"
End Sub


■メタ文字を使ってマッチするか判断する

メタ文字とは、文字そのものの意味とは別の役割をもった文字のことです。
メタ文字意味
.任意の一文字
[(文字列)][]内の任意の一文字
[^(文字列)][]内の文字列以外の任意の一文字。
[0-9]0~9のうち任意の一文字、[2-7]なら2~7の任意の一文字
\d0~9のうち任意の一文字。[0-9]は\dと同義
\D0~9以外の任意の一文字。[^0-9]。\d以外が\D
[a-zA-Z]任意のアルファベット一文字
\w[a-zA-Z_0-9]と同義
\W\w以外。[^a-zA-Z_0-9]。
\s空白文字(半角スペース,タブ,改行)の任意の一文字
\s空白文字(半角スペース,タブ,改行)以外の任意の一文字
\メタ文字をエスケープする


<.⇒任意の一文字にマッチ>
Sub SampleCode2()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")

    Reg.Pattern = "あん." '正規表現セット    
    If Reg.Test("あんい") Then Debug.Print "あんい:match!"  'マッチする
    If Reg.Test("あんき") Then Debug.Print "あんき:match!"  'マッチする
    If Reg.Test("あん♪") Then Debug.Print "あん♪:match!"  'マッチする
    Debug.Print "---"
End Sub


<[(文字列)]⇒[]内の任意の一文字にマッチ>
Sub SampleCode3()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")

    Reg.Pattern = "あん[いき♪]" '正規表現セット    
    If Reg.Test("あんい") Then Debug.Print "あんい:match!"  'マッチする
    If Reg.Test("あんこ") Then Debug.Print "あんこ:match!"  'マッチしない
    If Reg.Test("あんき") Then Debug.Print "あんき:match!"  'マッチする
    If Reg.Test("あんま") Then Debug.Print "あんま:match!"  'マッチしない
    If Reg.Test("あん♪") Then Debug.Print "あん♪:match!"  'マッチする
    Debug.Print "---"
End Sub

正規表現が:あん[いき♪] の場合、
「あ」と「ん」と[]内の文字のどれかをあわせた3文字が一致した時にマッチとなります。
つまり、下記の3文字とマッチした時です。
あんい
あんき
あん♪


<[^(文字列)]⇒[]内の文字列以外の任意の一文字にマッチ>
Sub SampleCode4()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")

    Reg.Pattern = "あん[^いき♪]" '正規表現セット
    If Reg.Test("あんい") Then Debug.Print "あんい:match!"  'マッチしない
    If Reg.Test("あんこ") Then Debug.Print "あんこ:match!"  'マッチする
    If Reg.Test("あんき") Then Debug.Print "あんき:match!"  'マッチししない
    If Reg.Test("あんま") Then Debug.Print "あんま:match!"  'マッチする
    If Reg.Test("あん♪") Then Debug.Print "あん♪:match!"  'マッチしない
    If Reg.Test("あん") Then Debug.Print "あん:match!"      'マッチしない
    Debug.Print "---"
End Sub
正規表現が:あん[^いき♪] の場合、
「あ」と「ん」と[]内の文字以外の3文字の時にマッチします


<[0-9]⇒0~9のうち任意の一文字にマッチ>
Sub SampleCode5()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")

    Reg.Pattern = "[0-9]" '正規表現セット    
    If Reg.Test("WindowsXP") Then Debug.Print "WindowsXP:match!"      'マッチしない
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  'マッチする
    Debug.Print "---"

    Reg.Pattern = "[5-8]" '正規表現セット
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  'マッチしない
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        'マッチする
    Debug.Print "---"
End Sub
[0123456789]と[0-9]は同義です。括弧内の文字列のうちどれか一つでも含んでいるとマッチになります。
2つ目の例である、[5-8]は[5678]と同義のため、5か6か7か8が一つでも含んでいるとマッチになります。


<[a-zA-Z]⇒任任意のアルファベット一文字にマッチ>
Sub SampleCode6()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "[a-z]" '正規表現セット
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  'マッチする
    If Reg.Test("EXCELVBA") Then Debug.Print "EXCELVBA:match!"        'マッチしない
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        'マッチしない
    Debug.Print "---"
End Sub
上の例は、小文字のアルファベットが一文字含んでいるときにマッチとなる例です。
よって、EXCELVBAは大文字のアルファベットなのでマッチしていません。


<\d,\D,\w,\W⇒数字、数字以外、アルファベットと_、アルファベットと_以外の一文字にマッチ>
Sub SampleCode7()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "\d" '正規表現セット 数字一文字にマッチ
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  '「2」にマッチする
    If Reg.Test("EXCELVBA") Then Debug.Print "EXCELVBA:match!"        'マッチしない
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        '「5」にマッチする
    If Reg.Test("正規表現") Then Debug.Print "正規表現:match!"        'マッチしない
    Debug.Print "---"
    
    Reg.Pattern = "\D" '正規表現セット 数字以外の一文字にマッチ
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  '「W」にマッチする
    If Reg.Test("EXCELVBA") Then Debug.Print "EXCELVBA:match!"        '「E」にマッチする
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        '「消」にマッチする
    If Reg.Test("正規表現") Then Debug.Print "正規表現:match!"        '「正」マッチする
    Debug.Print "---"

    Reg.Pattern = "\w" '正規表現セット アルファベットと_一文字にマッチ
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  '「W」にマッチする
    If Reg.Test("EXCELVBA") Then Debug.Print "EXCELVBA:match!"        '「E」にマッチする
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        '「5」にマッチする
    If Reg.Test("正規表現") Then Debug.Print "正規表現:match!"        'マッチしない
    Debug.Print "---"

    Reg.Pattern = "\W" '正規表現セット アルファベットと_以外一文字にマッチ
    If Reg.Test("Windows2000") Then Debug.Print "Windows2000:match!"  'マッチしない
    If Reg.Test("EXCELVBA") Then Debug.Print "EXCELVBA:match!"        'マッチしない
    If Reg.Test("消費税5%") Then Debug.Print "消費税5%:match!"        '「消」にマッチする
    If Reg.Test("正規表現") Then Debug.Print "正規表現:match!"        '「正」にマッチする
    Debug.Print "---"
End Sub


<\s,\S⇒空白文字(半角スペース,タブ,改行)またはそれ以外の任意の一文字にマッチ>
Sub SampleCode8()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "\s" '正規表現セット
    If Reg.Test("半角スペース:| |") Then Debug.Print "半角スペース:match!"   'マッチする
    If Reg.Test("全角スペース:| |") Then Debug.Print "全角スペース:match!"  'マッチしない
    If Reg.Test("タブ:|    |") Then Debug.Print "タブ:match!"                'マッチする
    If Reg.Test("タブ:|" & vbTab & "|") Then Debug.Print "タブ:match!"       'マッチする
    If Reg.Test("改行:|" & vbCrLf & "|") Then Debug.Print "CrLf:match!"      'マッチする
    If Reg.Test("改行:|" & vbCr & "|") Then Debug.Print "Cr:match!"          'マッチする
    If Reg.Test("改行:|" & vbLf & "|") Then Debug.Print "Lf:match!"          'マッチする
    Debug.Print "---"
End Sub
全角スペースにはマッチしないことだけは注意ですかね。
\Sを指定した場合は、上記以外の条件でマッチします。


<\⇒メタ文字をエスケープする>
Sub SampleCode9()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "\d" '正規表現セット
    If Reg.Test("\d") Then Debug.Print "\d:match!"  'マッチしない
    
    Reg.Pattern = "\\d" '正規表現セット
    If Reg.Test("\d") Then Debug.Print "\d:match!"  'マッチする
    
    Reg.Pattern = "x{2}"
    If Reg.Test("x{2}") Then Debug.Print "x{2}:match!"  'マッチしない
    
    Reg.Pattern = "x\{2}"
    If Reg.Test("x{2}") Then Debug.Print "x{2}:match!"  'マッチする
    
    Debug.Print "---"
End Sub
メタ文字を本来の文字としてマッチさせる為には、メタ文字の前に\をおけばよいです。
.の前、[の前、{の前、\の前ですね、"の前、
そして、後で触れる^の前、$の前、(の前



■繰返し表現を使ってマッチするか判断する

メタ文字意味
*0回以上繰り返す
+1回以上繰り返す
{m}m回繰り返す
{m,}m回以上繰り返す
{m,n}m回以上、n回以下繰り返す
?0回か1回繰り返す


<*⇒0回以上繰り返す場合にマッチ>
Sub SampleCode10()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "go*gle" '正規表現セット oはなくても一つ以上続いてもマッチ
    If Reg.Test("ggle") Then Debug.Print "ggle:match!"          'マッチする
    If Reg.Test("gogle") Then Debug.Print "gogle:match!"        'マッチする
    If Reg.Test("google") Then Debug.Print "google:match!"      'マッチする
    If Reg.Test("goooogle") Then Debug.Print "goooogle:match!"  'マッチする
    Debug.Print "---"
End Sub
正規表現:go*gle の場合
メタ文字の*の前の文字「o」は、無くてもいくつ続いてもマッチします。


<+⇒1回以上繰り返す場合にマッチ>
Sub SampleCode11()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "go+gle" '正規表現セット oが1つ以上ある時にマッチ
    If Reg.Test("ggle") Then Debug.Print "ggle:match!"          'マッチしない
    If Reg.Test("gogle") Then Debug.Print "gogle:match!"        'マッチする
    If Reg.Test("google") Then Debug.Print "google:match!"      'マッチする
    If Reg.Test("goooogle") Then Debug.Print "goooogle:match!"  'マッチする
    Debug.Print "---"
End Sub
正規表現:go+gle の場合
メタ文字の+の前の文字「o」は、一つ以上繰り返す場合にマッチします。


<{m}⇒m回繰り返す場合にマッチ>
Sub SampleCode12()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "go{1}gle" '正規表現セット oが1回続く時にマッチ
    If Reg.Test("ggle") Then Debug.Print "ggle:match!"          'マッチしない
    If Reg.Test("gogle") Then Debug.Print "gogle:match!"        'マッチする
    If Reg.Test("google") Then Debug.Print "google:match!"      'マッチしない
    If Reg.Test("goooogle") Then Debug.Print "goooogle:match!"  'マッチしない
    Debug.Print "---"
End Sub


<{m,}⇒m回以上繰り返す場合にマッチ>
Sub SampleCode13()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "go{1,}gle" '正規表現セット oが1回以上続く時にマッチ
    If Reg.Test("ggle") Then Debug.Print "ggle:match!"          'マッチしない
    If Reg.Test("gogle") Then Debug.Print "gogle:match!"        'マッチする
    If Reg.Test("google") Then Debug.Print "google:match!"      'マッチする
    If Reg.Test("goooogle") Then Debug.Print "goooogle:match!"  'マッチする
    Debug.Print "---"
End Sub


<{m,n}⇒m回以上n回以下繰り返す場合にマッチ>
Sub SampleCode14()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "go{1,2}gle" '正規表現セット oが1回以上2回以下続く時にマッチ
    If Reg.Test("ggle") Then Debug.Print "ggle:match!"          'マッチしない
    If Reg.Test("gogle") Then Debug.Print "gogle:match!"        'マッチする
    If Reg.Test("google") Then Debug.Print "google:match!"      'マッチする
    If Reg.Test("goooogle") Then Debug.Print "goooogle:match!"  'マッチしない
    Debug.Print "---"
End Sub


<?⇒1回以上繰り返す場合にマッチ>
Sub SampleCode15()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "html?" '正規表現セット
    If Reg.Test("test.html") Then Debug.Print "test.html:match!"  'マッチする
    If Reg.Test("test.htm") Then Debug.Print "test.htm:match!"    'マッチする
    Debug.Print "---"
End Sub
htmとhtmlのように一部の文字があるかないかと言った時にメタ文字?を使います。
まだ、メモしていませんが、括弧表現を使うと
VB(Script)? でVBとVBScriptにマッチさせれます




■IgnoreCaseを使ってマッチするか判断する
<IgnoreCaseプロパティ⇒(デフォルト)False:大文字小文字区別する、True:大文字小文字区別しない>
たとえば、ある文章の中に書かれているvbscriptにマッチさせて数を数えようとした場合
どこが大文字でどこが小文字で書くかは、人それぞれになってしまいます。
そこで、大文字小文字を気にしない場合は、IgnoreCaseプロパティをTrueに設定します。
デフォルトは、False
Sub SampleCode16()
    Dim Reg As Object
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "vbscript" '正規表現セット IgnoreCaseはセットしない=大文字小文字を区別する
    
    If Reg.Test("VBScript") Then Debug.Print "VBScript:match!"  'マッチしない
    If Reg.Test("vbscript") Then Debug.Print "vbscript:match!"  'マッチする
    If Reg.Test("vBsCrIpT") Then Debug.Print "vbscript:match!"  'マッチしない
    
    Reg.IgnoreCase = True '大文字小文字を区別しない
    If Reg.Test("VBScript") Then Debug.Print "VBScript:match!"  'マッチする
    If Reg.Test("vbscript") Then Debug.Print "vbscript:match!"  'マッチする
    If Reg.Test("vBsCrIpT") Then Debug.Print "vbscript:match!"  'マッチする
    Debug.Print "---"
End Sub



■マッチした内容を取り出す
<1つマッチした内容を取り出す>
Testメソッドではマッチするかしないかしか判別できない為
Executeメソッドを使って、マッチした時の詳細情報を取得する必要があります。
1つだけマッチした後に、使えるプロパティは以下の通りです
Sub SampleCode17()
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "\d+" '正規表現セット
    Set result = Reg.Execute("消費税10%") '検査する文字列
    If 0 < result.Count Then
        Debug.Print "マッチした数  :" & result.Count               '1
        Debug.Print "何文字目にマッチ:" & result.Item(0).FirstIndex  '3(最初の文字にヒットすると0)
        Debug.Print "マッチの文字数 :" & result.Item(0).Length      '2
        Debug.Print "マッチした文字列:" & result.Item(0).Value       '10
    End If

    Debug.Print "---"
End Sub
マッチ結果オブジェクト.Count   ⇒ マッチした数 マッチ結果オブジェクト.Item(0).FirstIndex ⇒ 何文字目にマッチしたか。ただし最初の文字は0とする <複数マッチした内容を取り出すGlobalプロパティ>
Sub SampleCode18()
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "\w{3}" '正規表現セット
    Reg.Global = True
    
    Set result = Reg.Execute("abcdefghijklmnop") '検査する文字列
    Dim i As Integer
    If 0 < result.Count Then
        Debug.Print "マッチした数  :" & result.Count
        Debug.Print ""
        For i = 0 To result.Count - 1
            Debug.Print "何文字目にマッチ:" & result.Item(i).FirstIndex
            Debug.Print "マッチの文字数 :" & result.Item(i).Length
            Debug.Print "マッチした文字列:" & result.Item(i).Value
            Debug.Print "---"
        Next
    End If

    Debug.Print "---------"
End Sub
実行結果--
マッチした数  :5
何文字目にマッチ:0
マッチの文字数 :3
マッチした文字列:abc
---
何文字目にマッチ:3
マッチの文字数 :3
マッチした文字列:def
---
何文字目にマッチ:6
マッチの文字数 :3
マッチした文字列:ghi
---
何文字目にマッチ:9
マッチの文字数 :3
マッチした文字列:jkl
---
何文字目にマッチ:12
マッチの文字数 :3
マッチした文字列:mno
---
---------
<()を使ってマッチした内容の一部を取り出す>
()には、二つの役割があります
一つは正規表現をグループとして扱う場合
VB(Script)?
とした場合
Script
という塊がある時とない時にマッチします。
もう一つの役割が括弧内の内容を記憶してSubMatchesプロパティで取り出すことができます。
以下のコードでは、郵便番号の3桁部と4桁部と3桁-4桁部を括弧でくくっています。
注意するべき点は、括弧をネストした場合どこから表示されるかということでしょうか?
では、サンプルコードです。
Sub SampleCode19()
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "〒((\d{3})-(\d{4}))" '正規表現セット
    
    Set result = Reg.Execute("〒123-4567") '検査する文字列
    Dim x As Integer, y As Integer
    If 0 < result.Count Then
        Debug.Print "マッチした数  :" & result.Count
        Debug.Print ""
        For x = 0 To result.Count - 1
            Debug.Print "何文字目にマッチ:" & result.Item(x).FirstIndex
            Debug.Print "マッチの文字数 :" & result.Item(x).Length
            Debug.Print "マッチした文字列:" & result.Item(x).Value
            Debug.Print "()でヒットした数:" & result.Item(x).Submatches.Count
            
            If 0 < result.Item(x).Submatches.Count Then '()内でマッチした内容を表示
                For y = 0 To result.Item(x).Submatches.Count - 1
                    Debug.Print result.Item(x).Submatches.Item(y)
                Next
            End If
        Next
    End If

    Debug.Print "---"
End Sub
実行結果---
マッチした数  :1

何文字目にマッチ:0
マッチの文字数 :9
マッチした文字列:〒123-4567
()でヒットした数:3
123-4567
123
4567
---

括弧がネストしている場合は、左側の括弧"("が登場した順番に表示されます
1.全体をくくる括弧 ((\d{3})-(\d{4}))
2.\d{3}をくくる括弧 ((\d{3})-(\d{4}))
3.全体をくくる括弧 ((\d{3})-(\d{4}))

ちなみに、始まり括弧"("の後に"?:"をつけるとメモリに記憶されません。
どういうことかと言うと、括弧にはグループとしての役割と括弧内の文字列をメモリに記憶するという二つの役割があるわけですが、前者の役割のうち定形文字列をグループとした場合マッチした内容は改めて取り出す必要もないのでそういう場合に使います。

例:java(script)?
java と javascriptにマッチさせたい場合
この時、括弧の中身は定形の文なので改めて取り出す必要はないので
java(?:script)?
と、記載された場合メモリに記憶されません。

括弧でグルーピングしていった時にメモリの内容を取り出す際にFor文等のループで取り出すことになると思うのですが複数箇所括弧でくくったうち、その中に定型文があった時は除外したいですよねぇ。利用方法はそんな感じですね。

■位置条件を使ってマッチするか判断する。
メタ文字意味
^文字列の先頭にマッチ
$文字列の末尾にマッチ
\b単語区切りの後にマッチ
\B単語区切り以外の部分にマッチ
これについては、まとめてコードで確認していきましょう。
Sub SampleCode20()
    Dim Reg As Object, Result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Global = True
    
    Dim TestStr As String
    TestStr = "abcdefg hijklmn" & vbCrLf & "opqrstu" & vbCrLf & "vwxyzAB"
    
    Reg.Pattern = "^[a-zA-Z]{3}" '正規表現セット
    Set Result = Reg.Execute(TestStr) '検査する文字列
    Call DebugPrint(Reg, Result)
    Debug.Print "---------"
    
    Reg.Pattern = "[a-zA-Z]{3}$" '正規表現セット
    Set Result = Reg.Execute(TestStr) '検査する文字列
    Call DebugPrint(Reg, Result)
    Debug.Print "---------"
    
    Reg.Pattern = "\b[a-zA-Z]{3}" '正規表現セット
    Set Result = Reg.Execute(TestStr) '検査する文字列
    Call DebugPrint(Reg, Result)
    Debug.Print "---------"
    
    Reg.Pattern = "\B[a-zA-Z]{3}" '正規表現セット
    Set Result = Reg.Execute(TestStr) '検査する文字列
    Call DebugPrint(Reg, Result)
    Debug.Print "---------"
    
End Sub

Sub DebugPrint(Reg As Object, Result As Object)
    Debug.Print "正規表現:" & Reg.Pattern
    Dim x As Integer
    If 0 < Result.Count Then
        For x = 0 To Result.Count - 1
            Debug.Print "マッチした文字列:" & Result.Item(x).Value
        Next
    End If
End Sub
実行結果---
正規表現:^[a-zA-Z]{3}
マッチした文字列:abc
---------
正規表現:[a-zA-Z]{3}$
マッチした文字列:zAB
---------
正規表現:\b[a-zA-Z]{3}
マッチした文字列:abc
マッチした文字列:hij
マッチした文字列:opq
マッチした文字列:vwx
---------
正規表現:\B[a-zA-Z]{3}
マッチした文字列:bcd
マッチした文字列:efg
マッチした文字列:ijk
マッチした文字列:lmn
マッチした文字列:pqr
マッチした文字列:stu
マッチした文字列:wxy
マッチした文字列:zAB
---------

正規表現:^[a-z]{3}
"abcdefg hijklmn" & vbCrLf & "opqrstu" & vbCrLf & "vwxyzAB"

正規表現:[a-z]{3}$
"abcdefg hijklmn" & vbCrLf & "opqrstu" & vbCrLf & "vwxyzAB"

正規表現:\b[a-zA-Z]{3}
"abcdefg hijklmn" & vbCrLf & "opqrstu" & vbCrLf & "vwxyzAB"

正規表現:\B[a-zA-Z]{3}
"abcdefg
hijklmn" & vbCrLf & "opqrstu" & vbCrLf & "vwxyzAB"

尚、区切り文字となるのは\Wに該当するものです。 つまりアルファベット、数字、アンダーバー(_)以外です

■ | で複数の条件を使ってマッチするか判断する。
|の前後のどちらかを含むとマッチとなります。
Sub SampleCode21()
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "abc|def" '正規表現セット
    Set result = Reg.Execute("abc")
    If result.Count Then Debug.Print result.Item(0).Value
    Set result = Reg.Execute("def")
    If result.Count Then Debug.Print result.Item(0).Value

    Reg.Pattern = "ab(c|d)ef" '正規表現セット
    Set result = Reg.Execute("abcef")
    If result.Count Then Debug.Print result.Item(0).Value
    Set result = Reg.Execute("abdef")
    If result.Count Then Debug.Print result.Item(0).Value

    
    Debug.Print "---"
End Sub
実行結果---
abc
def
abcef
abdef
---

■後方参照を使ってマッチするか判断してみる
問題。
wii、seeといったように3文字で2文字目と3文字目が同じ文字だけど
1文字目とは違うといった文字列はどのようにマッチさせればよいでしょう?
残念ながら、今までやってきた方法では表現できません。。

結論から言うと「\(数字)」を使います。
()でを使ってマッチさせた場合メモリにその内容が記録されます。
それと同時にマッチした順番に\1、\2、\3…といった順番に
()内の内容が正規表現内で利用できるようになります。

seeやwiiにマッチさせたい時は、下記のように書きます。
[a-zA-Z]([a-zA-Z])\1
Sub SampleCode22()
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "[a-zA-Z]([a-zA-Z])\1"
    
    Set result = Reg.Execute("Wii")
    If result.Count Then Debug.Print result.Item(0).Value 'Wii

    Set result = Reg.Execute("see")
    If result.Count Then Debug.Print result.Item(0).Value 'see
End Sub
■マッチした内容を置換する
Sub SampleCode22()
    Dim Reg As Object, result As Object, str As String
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "\d"
    Reg.Global = True
    
    str = Reg.Replace("ab2489c19d210e2190f1g082hi102jk1l1mn", "") '数字を全て空文字に置換
    Debug.Print str 'abcdefghijklmn
End Sub
■マッチした内容を置換する2
さて問題です。文字列中にあるjavascriptをscriptjavaにするにはどうしたらよいでしょうか?
Sub SampleCode23()
    Dim Reg As Object, result As Object, str As String
    Set Reg = CreateObject("VBScript.RegExp")
    Reg.Pattern = "(java)(script)"
    Reg.IgnoreCase = True
    
    str = Reg.Replace("好きな言語JavaScriptです", "$2$1") '前後入れ替える
    Debug.Print str '好きな言語ScriptJavaです
End Sub
■最後に、時計の正規表現を改めて考えてみる
0:00から23:59分を表現する正規表現を考える。
分に関しては、常に10の桁が0-6、1の桁が0-9の固定。
:[0-5][0-9]となる。
時間の方は、場合分けが発生する
10の桁がない時、1の桁0-9
10の桁が1の時、1の桁0-9
10の桁が2の時、0-3

以上を合わせるとこうなる。
 ([0-9]|1[0-9]|2[0-3]):[0-5][0-9]

最初の、[0-9]|1[0-9]の部分は1がある時とない時なので1?[0-9]にまとめれます
(1?[0-9]|2[0-3]):[0-5][0-9]

[0-9]は\dで表現できるので
(1?\d|2[0-3]):[0-5]\dで表現されます。

0 件のコメント: