印刷用ページ       送信     
クリックして評価とフィードバックをお寄せください
MSDN
MSDN ライブラリ
テクニカルドキュメント
コラム
Scripting Clinic
 Clinick's Clinic on Scripting: 正規表現...

  低帯域幅での表示をオンにする
Clinick's Clinic on Scripting: 正規表現による Visual Basic Scripting Edition (VBScript) の機能強化

Vernon W. Hui

May 10, 1999
日本語版最終更新日 1999 年 5 月 27 日

まさにインターネット時間での暮らしです。Microsoft® Scripting Technologiesチームが Visual Studio® 6.0 のためにスクリプティング エンジンの Version 4.0 をリリースしたのは、たった9か月前のことでした。いま、Internet Explorer 5.0 のリリースに伴い、われわれはスクリプト エンジンの Version 5.0 を送り出したところです。新機能が満載されたこの新バージョンには、HTML と ASP のパフォーマンスの改善、スクリプト エンコーディング、そして VBScript® および JScript® 言語の数々の機能が含まれています。この記事では、VBScript に最も多くの要望が寄せられた機能、正規表現について説明します。

正規表現とは何か?

そもそも正規表現とは何なのでしょうか? 正規表現は、複雑なパターン マッチングと、テキストの検索置換アルゴリズムを開発するためのツールです。Perl、egrep、awk、または sed を使っている開発者に尋ねれば、正規表現がテキストとデータを操作するための最も強力なユーティリティであると証言してくれるでしょう。特定の文字列にマッチするパターンを作成することで、開発者はデータの検索、抽出、または置換を完全に制御することができます。簡単に述べると、正規表現をマスターすることは、データをマスターすることにつながります。

この記事では、VBScript の正規表現に関連するすべてのオブジェクトについて説明し、一般的な正規表現パターンを要約した後、コードの中での正規表現の使用例をいくつか示します。

VBScript RegExp オブジェクト

VBScript Version 5.0 には、正規表現がオブジェクトとして用意されています。設計上、VBScript の RegExp オブジェクトは JScript の RegExp および String オブジェクトと似ていますが、構文上は Visual Basic との一貫性があります。まず最初に、オブジェクトとそのプロパティおよびメソッドについて説明します。VBScript の RegExp オブジェクトは、ユーザーに対してそれぞれ3つのプロパティとメソッドを提供します。

プロパティ メソッド
Pattern Test (検索文字列)
IgnoreCase Replace (検索文字列, 置換文字列)
Global Execute (検索文字列)

  • Pattern - 正規表現を定義するために使用される文字列。これは正規表現オブジェクトを使用する前に設定されていなくてはなりません。パターンについては後に詳しく説明します。
  • IgnoreCase - 大文字小文字を区別するかどうかを示す読み取り専用のブール値。デフォルトでは、IgnoreCase は False に設定されています。
  • Global - 正規表現を文字列内のすべての可能なマッチに対してテストすべきかどうかを示す読み取り専用のブール値。デフォルトでは、GlobalFalse に設定されています。
  • Test (文字列) - Test メソッドは、引数として文字列を取り、正規表現がその文字列に対してマッチした場合には True を、そうでない場合には False を返します。
  • Replace (検索文字列, 置換文字列) - Replace メソッドは、引数として2つの文字列を取ります。検索文字列の中で正規表現のマッチに成功すると、そのマッチしたものを置換文字列に置き換えて、新しい文字列を返します。マッチするものが見つからなかった場合は、元の検索文字列が返されます。
  • Execute (検索文字列) - Execute メソッドは Replace に似ていますが、成功したマッチの Matche オブジェクトを含んでいる Matches コレクション オブジェクトを返す点が異なります。元の文字列を変更はしません。

サンプルコードなど、詳細につきましては、Windows Script Technologies サイト をご覧ください。

VBScript Matches コレクション オブジェクト

前に述べたように、Matches コレクション オブジェクトは Execute メソッドの結果としてのみ返されます。このコレクション オブジェクトはゼロ個以上の Match オブジェクトを含むことができ、このオブジェクトのプロパティは読み取り専用です。


プロパティ
Count
Item

  • Count - コレクション内の Match オブジェクトの数を含んでいる読み取り専用の値。
  • Item - Matches コレクション オブジェクトから Match オブジェクトにランダムにアクセスできるようにする読み取り専用の値。また、For-Next ループを使えば、 Matches コレクション オブジェクトから Match オブジェクトにインクリメンタルにアクセスすることができます。

サンプルコードなど、詳細につきましては、Windows Script Technologies サイト をご覧ください。

VBScript Match オブジェクト

個々の Matches コレクション オブジェクトには、ゼロ個以上の Match オブジェクトが含まれています。これらは、正規表現を使ったときのマッチをそれぞれ表しています。これらのオブジェクトのプロパティも読み取り専用で、個々のマッチに関する情報を含んでいます。


プロパティ
FirstIndex
Length
Value

  • FirstIndex - 元の文字列内のマッチが起こった位置を含んでいる読み取り専用の値。このインデックスは位置の記録に 基点を 0 とするオフセットを使用しており、文字列の最初の位置は 0 から始まります。
  • Length - マッチした文字列の合計の長さを含んでいる読み取り専用の値。
  • Value - マッチした値またはテキストを含んでいる読み取り専用の値。これはまた、Match オブジェクトにアクセスするときの既定値でもあります。

サンプルコードなど、詳細につきましては、Windows Script Technologies サイト をご覧ください。

パターンとはどのようなものか?

では、パターンとはどういう形をしているものなのでしょうか? 正規表現はそれ自身が1つの言語といってもいいようなものですが、Perl を使っているユーザーにはすぐに理解できるでしょう。VBScript のパターン セットは Perl をもとにしており、そのコアの機能は Perl に似ています。ここでは正規表現を定義するために使用されるパターンをいくつか説明します。これらのセットはいくつかの領域に分類することができます。

位置マッチング

位置マッチングでは、^ と $ を使って、文字列の始まりまたは終わりを検索することができます。パターン プロパティを "^VBScript" に設定すると、"VBScript is cool" にはマッチしますが、"I like VBScript" にはマッチしません。

シンボル機能
^ 文字列の先頭にのみマッチします。
"^A" は "An A+ for Anita" の最初の "A" にマッチします。
$ 文字列の末尾にのみマッチします。

"t$" は "A cat in the hat" の最後の "t" にマッチします。
\b 任意の単語境界にマッチします。

"ly\b" は "possibly tomorrow" の "ly" にマッチします。
\B 任意の単語境界以外の位置にマッチします。

リテラル

リテラルとは、英数字、ASCII、8進文字、16進文字、UNICODE、または特殊なエスケープ文字のことです。一部の文字は特殊な意味を持っているので、これらの文字を使用するためにはエスケープする必要があります。正規表現でこの種の特殊文字にマッチさせるためには、文字の前に "\" を置きます。

シンボル機能
英数字 英字と数字に文字どおりにマッチします。
\n 改行にマッチします。
\f フォーム フィードにマッチします。
\r キャリッジ リターンにマッチします。
\t 水平タブにマッチします。
\v 垂直タブにマッチします。
\? ? にマッチします。
\* * にマッチします。
\+ + にマッチします。
\. . にマッチします。
\| | にマッチします。
\{ { にマッチします。
\} } にマッチします。
\\ \ にマッチします。
\[ [ にマッチします。
\] ] にマッチします。
\( ( にマッチします。
\) ) にマッチします。
\xxx 8進数 xxx によって表現されるASCII文字にマッチします。

"\50" は "("、すなわち chr (40) にマッチします。
\xdd 16進数 dd によって表現されるASCII文字にマッチします。

"\x28" は "("、すなわち chr (40) にマッチします。
\uxxxx UNICODE xxxx によって表現されるASCII文字にマッチします。

"\u00A3" は "£" にマッチします。

文字クラス

文字クラスにより、表現を [] の角括弧で囲むことで、グループのカスタマイズを行うことができます。[] の中の先頭の文字として^を指定すると、文字クラスの否定形を作ることができます。また、ダッシュを使うと文字の範囲を表すことができます。たとえば、正規表現 "[^a-zA-Z0-9]" は英数字以外のすべての文字にマッチします。さらに、いくつかの一般的な文字セットが、エスケープに文字を続けたものとして定義されています。


シンボル機能
[xyz] 文字セットに含まれている任意の1文字にマッチします。

"[a-e]" は "basketball" の中の "b" にマッチします。
[^xyz] [^xyz] 文字セットに含まれていない任意の1文字にマッチします。

"[^a-e]" は "basketball" の中の "s" にマッチします。
. \n 以外の任意の文字にマッチします。
\w 単語に使用される任意の文字にマッチします。[a-zA-Z_0-9]と等価。
\W 単語に使用される文字以外の任意の文字にマッチします。[^a-zA-Z_0-9]と等価。
\d 任意の数字にマッチします。[0-9]と等価。
\D 任意の数字以外の文字にマッチします。[^0-9]と等価。
\s 任意のスペース文字にマッチします。[ \t\r\n\v\f]と等価。
\S 任意の非スペース文字にマッチします。[^ \t\r\n\v\f]と等価。

繰り返し

繰り返しにより、正規表現の中の句を複数回検索することができます。繰り返しマッチングを使うと、正規表現の中で要素が何回繰り返されるかを指定することができます。

シンボル機能
{x} 正規表現のちょうど x個の直前の文字にマッチします。

"\d{5}" は5桁の数字にマッチします。
{x,} 正規表現のx個以上の直前の文字にマッチします。

"\s{2,}" は2個以上のスペース文字にマッチします。
{x,y} 正規表現のx個以上、y個以下の直前の文字にマッチします。

"\d{2,3}" は2個以上、3個以下の数字にマッチします。
? ゼロ個または1個の直前の文字にマッチします。{0,1}と等価。

"a\s?b" は "ab" または "a b" にマッチします。
* ゼロ個以上の直前の文字にマッチします。{0,}と等価。
+ 1個以上の直前の文字にマッチします。{1,}と等価。

選択とグループ化

選択とグループ化は、より複雑な正規表現を作成するために使用されます。選択とグループ化のテクニックを使用すると、正規表現の中に複雑な句を作成し、より柔軟に正規表現を制御することができます。

シンボル機能
() 複数の句をグループ化して、1つの句を作成します。ネストすることができます。 "(ab)?(c)" は "abc" または "c" にマッチします。
| 選択は、複数の句を1つの正規表現にまとめ、これらのうちの任意の句にマッチします。

"(ab)|(cd)|(ef)" は "ab" または "cd" または "ef" にマッチします。

後方参照

後方参照を使うと、プログラマは正規表現の一部を後方参照することができます。句を括弧で囲み、\ 文字の後に1つの数字を続けることによってその句を指定します。第1の括弧で囲まれた句は \1、第2の括弧で囲まれた句は \2 として参照できます。

シンボル機能
()\n n番目の括弧で囲まれた句にマッチします。

"(\w)+\s+\1" は、"hubba hubba" のように、1行に2回現れる任意の単語にマッチします。

実際の例

ここで示す例は、この記事で説明してきたいくつかの機能を使用しています。これは正規表現を使って、有効な入力が行われたかどうかをテストする単純なアプリケーションです。有効な入力が行われるまで、ユーザーに対して繰り返し入力を求めます。まず、最初のパターンを詳しく説明します。

"^\s*((\$\s?)|(£\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$"
  • "^\s*…" と "…\s*$" - 先頭と末尾に任意の数のスペース文字が存在していてよく、入力は1つの行にそれ単独で行われなくてはならないという意味です。
  • "((\$\s?)|(£\s?))?" - オプションのスペースの後に、オプションの $ または£ 記号が存在していてよいという意味です。
  • "((\d+(\.(\d\d)?)?)|(\.\d\d))" - 少なくとも1つの数字の後に、オプションとして小数点と(オプションの)2つの数字、または小数点と2つの数字が続いている文字列を検索します。つまり、6.、23.33、.88などの入力は許されますが、5.5は許されません。
  • "\s*(UK|GBP|GB|USA|US|USD)?" - 任意の数のスペース文字の後に、オプションとして、文字列に対して有効な引数を続けることができるという意味です。

この例では、ユーザーが米国ドルと英国ポンドのどちらかを入力したかどうかを判断するために正規表現を使用しています。まず £、UK、GBP、または GB という文字列を検索します。この正規表現が真であれば、ユーザーは英国ポンドの金額を入力したことになります。そうでなければ、USD の金額であると仮定します。

このコードを実行するには、これを CurrencyEx.vbs として保存して Windows Script Host を使って実行するか、VB にコピーするか(Microsoft VBScript Regular Expressions への参照を追加する必要があります)、コードを HTML ファイルに埋め込みます。

Sub CurrencyEx
Dim inputstr, re, amt
Set re = new regexp  'Create the RegExp object

'Ask the user for the appropriate information
inputstr = inputbox("I will help you convert USA and CAN currency. Please enter the amount to convert:")
'Check to see if the input string is a valid one.
re.Pattern = "^\s*((\$\s?)|(£\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$"
re.IgnoreCase = true
do while re.Test(inputstr) <> true
'Prompt for another input if inputstr is not valid
inputstr = inputbox("I will help you convert USA and GBP currency. Please enter the amount to(USD or GBP):")

loop

'Determine if we are going from GBP->US or USA->GBP
re.Pattern = "£|UK|GBP|GB"
if re.Test(inputstr) then
'The user wants to go from GBP->USD
 
re.Pattern = "[a-z$£ ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 1.6368
amt = cdbl(cint(amt * 100) / 100)
amt = "$" & amt
else
'The user wants to go from USD->GBP

re.Pattern = "[a-z$£ ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 0.609
amt = cdbl(cint(amt * 100) / 100)
amt = "£" & amt
end if

msgbox ("Your amount of: " & vbTab & inputstr & vbCrLf & "is equal to: " & vbTab & amt)
End sub


さらに強力に利用する

Visual Basic 開発者が正規表現を有効に使えるように、VBScript の正規表現エンジンは COM オブジェクトとして実装されています。つまり、Visual Basic や C などの、VBScript の外部のさまざまなソースからエンジンを呼び出すことができるので、非常に強力です。ここで示す例は、Outlook® 97、Outlook 98、または Outlook 2000 の連絡先リストを調べて、特定の都市に住んでいる連絡先の名前を返す小さな Visual Basic アプリケーションです。

このプログラムは単純です。まず、検索する都市の名前をカンマで区切って入力するようにユーザーに求めます。次に、Outlook 内に新しく作成する連絡先フォルダの名前を入力するように求めます。マッチした連絡先は、新しく作成された連絡先フォルダにコピーされます。

Microsoft VBScript Regular Expressions オブジェクト ライブラリへの参照を追加することで、Early binding を行うことができます。Early binding にはいくつかの利点があります。たとえば実行が高速になり、プログラムのコーディングも簡単になります。参照をオブジェクトに追加し、VBScript のコードを切り取って、VB に直接貼り付ければ、正規表現が直ちに使えるようになります。

正規表現と同じように、また同じ理由から、Outlook 2000 オブジェクト ライブラリに対する参照も追加しています。もちろん CreateObject() を使ってCOM 呼び出しを行うことは可能ですが、こちらの方法の方が簡単です。これらのオブジェクトを作成した後は、連絡先フォルダにアクセスし、都市の名前のマッチングを行うという単純なコードを実行します。2つのコレクション オブジェクトを比較し、両者が等しいかどうかを調べる小さなヘルパー関数、compareCollectionObjects(x,y) を使用しています。

このプログラムを実行するには、コードを VB にコピーし(参照を追加しておく必要があります)、関数 FindCityContacts() を呼び出してください。

Sub FindCityContacts()

    Dim strTemp
    Dim index
    Dim citySearch
    Dim myNameSpace, myContacts, newCityContacts, newCityContactsName
    Dim contact
    Dim newContact

    'Set the early binding objects
    Dim re as New RegExp  
    Dim myApp as New Outlook.Application

    re.Global = True
    re.IgnoreCase = True

    citySearch = InputBox("Please enter the cities of your search, separated by commas.")
    newCityContactsName = InputBox("Please enter the new contact folder name")

    'Set some of the objects and create the new Contacts folder
    Set myNameSpace = myApp.GetNamespace("MAPI")
    'olFolderContacts = 10
    Set myContacts = myNameSpace.GetDefaultFolder(10)   
    Set newCityContacts = myContacts.Folders.Add(newCityContactsName)

    'Set cities, using regular expressions to contain the city names
    re.Pattern = "[^,]+"
    Set cities = re.Execute(citySearch)
    For Each city In cities

       'Set citytokens to be the individual tokens in the city name
       'Then we compare them to the address tokens in each contact
        re.Pattern = "[^ ]+"
        Set citytokens = re.Execute(city)

        For i = 1 to myContacts.Items.Count
            re.Pattern = "[^ ]+"
            Set contact = myContacts.Items.Item(i)

            Set HomeAddressCityTokens = re.Execute(contact.HomeAddressCity)
            If compareCollectionObjects(HomeAddressCityTokens, citytokens) = 1 Then

                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If

            Set OtherAddressCityTokens = re.Execute(contact.OtherAddressCity)
            If compareCollectionObjects(OtherAddressCityTokens, citytokens) = 1 Then
                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If

            Set BusinessAddressCityTokens = re.Execute(contact.BusinessAddressCity)
            If compareCollectionObjects(BusinessAddressCityTokens, citytokens) = 1 Then
                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If
        Next
    Next

MsgBox "done"

End Sub

'This function is provided as a helper-function 
' to compare two collection objects.
Function compareCollectionObjects(x, y)

    Dim index
    Dim flag
    flag = 1

    If x.Count <> y.Count Then
        flag = 0
    Else
        index = x.Count

        For i = 0 To (index - 1)
            If StrComp(x.Item(i), y.Item(i), 1) Then
                flag = 0
            End If
        Next
    End If

    compareCollectionObjects = flag

End Function

まとめ

これまで見てきたように、Microsoft は、Version 5.0 において VBScript を正規表現によって強化しています。正規表現は、VBScript と JScript の堅牢さを比較する際の最も大きな格差の1つでした。このスクリプティング エンジン Version 5.0 では、VBScript の機能セットを改良することに重点が置かれています。正規表現が追加されたことにより、データをより細かく制御することができ、クライアントとサーバーの両方でより強力な webアプリケーションを作成することができます。

関連情報:

「Mastering Regular Expressions」 Jeffrey E. F. Friedl 著
邦訳 『詳説 正規表現』 歌代和正 監訳 春遍雀來、鈴木武生 共訳

Windows Script Technologies サイト

Vernon W. Hui は Microsoft Scripting Technologies グループのソフトウェア テスト エンジニアです。余暇には、バスケットボールをしたり、イリノイ州の Chicago と Urbana にいる親友とネットワーク ゲームを楽しんだりしています。


© 2009 Microsoft Corporation. All rights reserved. 使用条件  |  商標  |  プライバシー
Page view tracker