Delphiでマイクロソフト製の正規表現ライブラリを使う
他の開発環境にあるのにDelphiに備わっていない機能の1つに「正規表現」があります。なぜ備わってないのか不思議でなりませんが(Delphi IDEの検索ダイアログには「正規表現」オプションがあるのに…)、ないものは仕方ないのでどこからか調達してくる必要があります。
有名どころでは
などですね。ただ、どれも一長一短で決め手に欠ける感じで、実際に全部試したほうがいいと思います。
で、もう1つの選択肢として、マイクロソフトが提供している「Microsoft VBScript Regular Expression ライブラリ」を使う方法があります。「VBScript」の名の通り、本来はHTMLの中に埋め込んだVBScriptやWindows Scripting Host(WSH)で使うことを想定しています。しかし、本体がActiveX(=COM)なので、ActiveXに対応した開発環境ならば呼び出して使うことが出来るのです。
外部ライブラリの仕様には抵抗を感じる人もいるでしょうが、しかし、
試すだけならタダですから、とりあえず使ってみましょう。
これで「VBScript_RegExp_55_TLB.pas」がDelphiのImportsフォルダに作成されます。
しかし、悲しいことにこのユニットは不完全で、そのままでは使い物になりません。そのため、ソースコードを一部改良します。
◆改良後のソースコードをダウンロードできます。
(このファイルさえあれば、上述したタイプライブラリの取り込み作業は不要です。Importsフォルダに入れるだけで使えるようになります。)
改良前
|
改良後
|
この正規表現ライブラリは、4つのクラスを持っています。すなわち
MatchCollection・Match・SubMatchesは、TRegExp.Executeメソッドを実行した場合のみ関係するクラスです。
さらに各クラスを詳細に見ていきましょう。
TRegExpメンバー | 型・定義 | 解説 |
---|---|---|
プロパティ | ||
Global | WordBool | 正規表現パターンにあたる文字列が検索対象内に複数存在する可能性のある場合、Trueだと複数の検索結果が返ってきます。Falseだと最初に該当した結果のみ返ってきます。 |
IgnoreCase | WordBool | 大文字小文字を無視して検索します。 |
Multiline | WordBool | 検索対象が複数行の場合、Trueだと各行を個別に検索します。Falseだと文字列全体として検索します。これは正規表現パターンの「^ 」や「$ 」に影響します。 |
Pattern | WideString | 正規表現パターンを入れます。Perlのようにスラッシュで囲う必要はありません。 |
メソッド | ||
Execute | function Execute(const sourceString: WideString): IDispatch; ※実際はMatchCollectionが返る | 検索対象文字列sourceStringでパターン文字列Patternを実行します。パターンにマッチした情報がMatchCollectionとして返ってきます。GlobalがTrueの場合は複数の検索結果が返ってくる場合があります。sourceStringに検索対象文字列を指定します。 |
Replace | function Replace(const sourceString: WideString; replaceVar: OleVariant): WideString; | 検索対象文字列sourceStringの中でパターン文字列Patternがマッチした場合にその文字列をreplaceVarで置換します。置換した結果が文字列として返ってきます。sourceStringに検索対象文字列を指定します。replaceVarに置換する値を指定します。replaceVarはOleVariant型なので文字列以外に数値なども直接指定できます。 |
Test | function Test(const sourceString: WideString): WordBool; | 検索対象文字列sourceStringの中でパターン文字列Patternがマッチするかテストします。マッチすればTrue、しなければFalseを返します。sourceStringに検索対象文字列を指定します。 |
メンバー | 型・定義 | 解説 |
---|---|---|
プロパティ | ||
Count | Integer | Itemプロパティの個数です。TRegExp.GlobalがFalseの場合は、0か1となります。 |
Item[index: Integer] | IDispatch ※実際はMatch | TRegExp.Executeメソッドの実行結果がMatchとして入っています。TRegExp.GlobalがTrueの場合は、複数の結果が入っていることがあります。 |
メソッド | ||
なし |
メンバー | 型・定義 | 解説 |
---|---|---|
プロパティ | ||
FirstIndex | Integer | パターンにマッチした文字列の検索対象文字列内での位置です。位置は0から始まります。 |
Length | Integer | パターンにマッチした文字列の長さです。 |
SubMatches | IDispatch ※実際はSubMatches | パターンに後方参照が含まれている場合、参照結果がSubMatchesとして入っています。 |
Value | WideString | パターンにマッチした文字列が入っています。 |
メソッド | ||
なし |
メンバー | 型・定義 | 解説 |
---|---|---|
プロパティ | ||
Count | Integer | Itemプロパティの個数です。 |
Item[index: Integer] | OleVariant | 後方参照の結果が入っています。 |
メソッド | ||
なし |
見慣れない型がいくつかありますが、これはActiveX(COM)用の型です。WordBoolはBooleanと同じようにTrue/Falseで使います。WideStringはstringのUnicode版です。OleVariantは何でも入る汎用の型です。詳しくはヘルプを見てください。
uses VBScript_RegExp_55_TLB; procedure TForm1.Button1Click(Sender: TObject); var Regexp: TRegExp; Matched: boolean; begin Regexp := TRegExp.Create(nil); try Regexp.IgnoreCase := True; //大文字小文字を区別しない Regexp.Pattern := '^delphi'; //正規表現パターン Matched := Regexp.Test('Delphi is the product of Borland.'); //テスト ShowMessage(BoolToStr(Matched, True)); finally Regexp.Free; end; end; |
実行結果:True |
uses VBScript_RegExp_55_TLB; procedure TForm1.Button2Click(Sender: TObject); var Regexp: TRegExp; Rep: string; begin Regexp := TRegExp.Create(nil); try Regexp.Global := True; //全部を対象とする Regexp.Pattern := '明日'; //正規表現パターン Rep := Regexp.Replace('明日は明日の風が吹く', 'あした'); //置換 ShowMessage(Rep); finally Regexp.Free; end; end; |
実行結果:あしたはあしたの風が吹く |
<備考>
|
uses VBScript_RegExp_55_TLB; procedure TForm1.Button3Click(Sender: TObject); var Regexp: TRegExp; Source: string; Rep: string; begin Regexp := TRegExp.Create(nil); try Regexp.IgnoreCase := True; Regexp.Pattern := '<a\s+href=["'']*([^>"'']*)["'']*>(.*?)</a>'; Source := '<a href=""http://www.yahoo.co.jp/"">Yahoo! Japan</a>'; Rep := Regexp.Replace(Source, 'URL=$1, Title=$2'); ShowMessage(Rep); finally Regexp.Free; end; end; |
実行結果:URL=http://www.yahoo.co.jp/, Title=Yahoo! Japan |
<備考>
|
uses VBScript_RegExp_55_TLB; procedure TForm1.Button4Click(Sender: TObject); const Pattern = '<a\s+href=["'']*([^>"'']*)["'']*>(.*?)</a>'; Source = '<a href="http://www.borland.co.jp/">日本ボーランド</a><a href="http://www.google.co.jp/">Google</a>'; var Regex: TRegExp; MatCol: MatchCollection; Mat: Match; SubMat: SubMatches; i: integer; begin Regexp := TRegExp.Create(nil); try Regex.IgnoreCase := True; //大文字小文字を区別しない Regex.Global := True; //全部を対象とする Regex.Pattern := Pattern; //正規表現パターン MatCol := Regex.Execute(Source) as MatchCollection; //実行 for i := 0 to MatCol.Count - 1 do begin Mat := MatCol.Item[i] as Match; SubMat := Mat.SubMatches as SubMatches; Memo1.Lines.Add(Mat.Value); //マッチした文字列 Memo1.Lines.Add(SubMat.Item[0]); //後方参照の文字列 Memo1.Lines.Add(SubMat.Item[1]); end; finally Regexp.Free; end; end; |
実行結果: <a href="http://www.borland.co.jp/">日本ボーランド</a> http://www.borland.co.jp/ 日本ボーランド <a href="http://www.google.co.jp/">Google</a> http://www.google.co.jp/ |
<備考>
|