Edit1 に入力された文字列が某外食チェーン店の名前に一致するか?
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
begin
if TRegEx.IsMatch(Edit1.Text, Exp, []) then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
以下のような記述も可能です。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
begin
if TRegEx.Match(Edit1.Text, Exp, []).Success then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
Edit1 に入力された文字列が某外食チェーン店の名前に一致したらその文字列を表示する。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
Match: TMatch;
begin
Match := TRegEx.Match(Edit1.Text, Exp, []);
if Match.Success then
ShowMessage(Match.Value)
else
ShowMessage('No match.');
end;
|
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
マッチ文字列の列挙
次に、正規表現文字列に一致するすべての文字列を列挙してみます。
コアクラス版
Memo1 に入力された文字列中に一致する某外食チェーン店の名前があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
RegExp: TSkRegExp;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
if RegExp.Exec(Memo1.Lines.Text) then
repeat
mValue := RegExp.Match[0];
mStart := RegExp.MatchPos[0];
mLength := RegExp.MatchLen[0];
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add(Dmy);
until (not RegExp.ExecNext);
finally
RegExp.Free;
end
|
|
Memo1 に入力された文字列中に一致する某外食チェーン店の名前があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
RegExp: TPerlRegEx;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Memo1.Lines.Text);
if RegExp.Match then
repeat
mValue := UnicodeString(RegExp.MatchedText);
mStart := RegExp.MatchedOffset; // UTF-8 での開始位置
mLength := RegExp.MatchedLength; // UTF-8 でのエレメント長
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add(Dmy);
until (not RegExp.MatchAgain);
finally
RegExp.Free;
end;
end;
|
コアクラスは UTF-8 で処理しているので、キャストしないと警告が出ます。また、マッチ開始位置やマッチ長は UTF-8 ベースなので、SelStart や SelLength に直接使う事はできません。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
RegExp: TPerlRegEx;
Dmy, mValue: String;
mStart, mLength: Integer;
U8: UTF8String;
begin
Memo2.Lines.Clear;
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Memo1.Lines.Text);
if RegExp.Match then
repeat
U8 := UTF8String(Memo1.Lines.Text);
mValue := UnicodeString(RegExp.MatchedText);
mStart := RegExp.MatchedOffset; // UTF-8 での開始位置
mLength := RegExp.MatchedLength; // UTF-8 でのエレメント長
U8 := Copy(U8, mStart, mLength);
Dmy := Format('%s (%s)', [mValue, UnicodeString(U8)]);
Memo2.Lines.Add(Dmy);
until (not RegExp.MatchAgain);
finally
RegExp.Free;
end;
end;
|
UTF8String で処理すればマッチ位置情報も使えない事はないですが...。
|
ラッパークラス版
Memo1 に入力された文字列中に一致する某外食チェーン店の名前があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
for Match in TRegEx.Matches(Memo1.Lines.Text, Exp) do
begin
mValue := Match.Value;
mStart := Match.Index;
mLength := Match.Length;
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add(Dmy);
end;
end;
|
for in do を使わないやり方は以下のようになります。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
i: Integer;
Collection: TMatchCollection;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
Collection := TRegEx.Matches(Memo1.Lines.Text, Exp);
for i:=0 to Collection.Count-1 do
begin
mValue := Collection.Item[i].Value;
mStart := Collection.Item[i].Index;
mLength := Collection.Item[i].Length;
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add(Dmy);
end;
end;
|
本来は以下のような記述も可能なハズです (QC#87752 です。XE2 で解決されています。SkRegularExpressions は最新版で動作します)。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
Match := TRegEx.Match(Memo1.Lines.Text, Exp);
while Match.Success do
begin
mValue := Match.Value;
mStart := Match.Index;
mLength := Match.Length;
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
ShowMessage(Dmy);
Match := Match.NextMatch;
end;
end;
|
.NET の RegEx の記述方法とは若干異なる事になりますが、TRegEx.Match を直接呼び出さなければ (クラスメソッドの方を使わなければ) QC#87752 を回避できるようです。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '[吉|\x{20BB7}]野[屋|家]';
var
RegEx: TRegEx;
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
RegEx := TRegEx.Create(Exp);
Match := RegEx.Match(Memo1.Lines.Text);
while Match.Success do
begin
mValue := Match.Value;
mStart := Match.Index;
mLength := Match.Length;
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
ShowMessage(Dmy);
Match := Match.NextMatch;
end;
end;
|
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
PerlRegEx のラッパークラスは UTF-16 ベースなのでコアクラスの時と違い、マッチ開始位置やマッチ長を SelStart や SelLength に使う事ができます。
|
文字列のグループマッチ
正規表現文字列に一致するかしないかを判定し、それぞれの項目をグループとして取得してみます。
正規表現では "()" で括られた部分を "グループ" として 1 から始まるインデックスで取り出す事ができ、さらに "(?<name>式)" のようにすると "名前付きグループ" にする事が可能で、name で指定した名前で取り出す事ができます。TDataSet.Fields / TDataSet.FieldByName のようなものです。
関数版
Edit1 に入力された文字列が日付文字列に一致するかをグループインデックスで取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(\d{2,4})\/(\d{1,2})\/(\d{1,2})';
var
MatchList: TStringList;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
MatchList := TStringList.Create;
try
if RegMatch(Exp, Edit1.Text, MatchList, []) then
begin
mDate := MatchList[0]; // All
mYear := StrToInt(MatchList[1]); // Group 1
mMonth := StrToInt(MatchList[2]); // Group 2
mDay := StrToInt(MatchList[3]); // Group 3
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
finally
MatchList.Free;
end;
end;
|
|
|
コアクラス版
Edit1 に入力された文字列が日付文字列に一致するかをグループインデックスで取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(\d{2,4})\/(\d{1,2})\/(\d{1,2})';
var
RegExp: TSkRegExp;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
if RegExp.Exec(Edit1.Text) then
begin
mDate := RegExp.Match[0];
mYear := StrToInt(RegExp.Match[1]);
mMonth := StrToInt(RegExp.Match[2]);
mDay := StrToInt(RegExp.Match[3]);
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
finally
RegExp.Free;
end;
end;
|
Edit1 に入力された文字列が日付文字列に一致するかをグループ名で取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Year>\d{2,4})\/(?<Month>\d{1,2})\/(?<Day>\d{1,2})';
var
RegExp: TSkRegExp;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
if RegExp.Exec(Edit1.Text) then
begin
mDate := RegExp.Match[0];
mYear := StrToInt(RegExp.NamedGroup['Year' ]);
mMonth := StrToInt(RegExp.NamedGroup['Month']);
mDay := StrToInt(RegExp.NamedGroup['Day' ]);
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
finally
RegExp.Free;
end;
end;
|
|
Edit1 に入力された文字列が日付文字列に一致するかをグループインデックスで取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(\d{2,4})\/(\d{1,2})\/(\d{1,2})';
var
RegExp: TPerlRegEx;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Edit1.Text);
if RegExp.Match then
begin
mDate := UnicodeString(RegExp.MatchedText);
mYear := StrToInt(UnicodeString(RegExp.Groups[1]));
mMonth := StrToInt(UnicodeString(RegExp.Groups[2]));
mDay := StrToInt(UnicodeString(RegExp.Groups[3]));
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
finally
RegExp.Free;
end;
end;
|
Edit1 に入力された文字列が日付文字列に一致するかをグループ名で取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
RegExp: TPerlRegEx;
Index: Integer;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Edit1.Text);
if RegExp.Match then
begin
mDate := UnicodeString(RegExp.MatchedText);
Index := RegExp.NamedGroup(UTF8String('Field1'));
mYear := StrToInt(UnicodeString(RegExp.Groups[Index]));
Index := RegExp.NamedGroup(UTF8String('Field2'));
mMonth := StrToInt(UnicodeString(RegExp.Groups[Index]));
Index := RegExp.NamedGroup(UTF8String('Field3'));
mDay := StrToInt(UnicodeString(RegExp.Groups[Index]));
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
finally
RegExp.Free;
end;
end;
|
この正規表現文字列の場合、名前付きグループのグループ名に何故か year や day を含められません (QC#93333)。
const
Exp = '(?<Year>\d{2,4})\/(?<Month>\d{1,2})\/(?<Day>\d{1,2})';
|
これだと NamedGroup の戻り値がおかしくなります。なお、QC#93333 は XE2 で修正されています。
|
ラッパークラス版
Edit1 に入力された文字列が日付文字列に一致するかをグループインデックスで取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(\d{2,4})\/(\d{1,2})\/(\d{1,2})';
var
Match: TMatch;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
Match := TRegEx.Match(Edit1.Text, Exp, []);
if Match.Success then
begin
mDate := Match.Value; // All
mYear := StrToInt(Match.Groups[1].Value); // Group 1
mMonth := StrToInt(Match.Groups[2].Value); // Group 2
mDay := StrToInt(Match.Groups[3].Value); // Group 3
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
end;
|
Edit1 に入力された文字列が日付文字列に一致するかをグループ名で取得し、Memo2 に表示。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
Match: TMatch;
mDate: string;
mYear, mMonth, mDay: Word;
begin
Memo2.Lines.Clear;
Match := TRegEx.Match(Edit1.Text, Exp, []);
if Match.Success then
begin
mDate := Match.Value; // All
mYear := StrToInt(Match.Groups['Field1'].Value); // Group 1
mMonth := StrToInt(Match.Groups['Field2'].Value); // Group 2
mDay := StrToInt(Match.Groups['Field3'].Value); // Group 3
Memo2.Lines.Add(mDate);
Memo2.Lines.Add(Format('Year = %d', [mYear ]));
Memo2.Lines.Add(Format('Month = %d', [mMonth]));
Memo2.Lines.Add(Format('Day = %d', [mDay ]));
end
else
Memo2.Lines.Add('No match.');
end;
|
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
|
グループマッチ文字列の列挙
次に、正規表現文字列に一致するすべての文字列をグループでも列挙してみます。
コアクラス版
Memo1 に入力された文字列中に一致する日付文字列があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Year>\d{2,4})\/(?<Month>\d{1,2})\/(?<Day>\d{1,2})';
var
i: Integer;
RegExp: TSkRegExp;
Dmy, mValue: String;
mStart, mLength: Integer;
gName: String;
begin
Memo2.Lines.Clear;
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
// RegExp.MultiLine := True;
if RegExp.Exec(Memo1.Lines.Text) then
repeat
mValue := RegExp.Match[0];
mStart := RegExp.MatchPos[0];
mLength := RegExp.MatchLen[0];
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for i:=1 to RegExp.GroupCount do
begin
// Group
gName := RegExp.GroupNameFromIndex[i];
Memo2.Lines.Add(Format(' Group : ''%s'' [%d]', [gName, i]));
// Value
mValue := RegExp.Match[i];
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := RegExp.MatchPos[i];
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := RegExp.MatchLen[i];
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
until (not RegExp.ExecNext);
finally
RegExp.Free;
end
end;
|
|
Memo1 に入力された文字列中に一致する日付文字列があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
i: Integer;
RegExp: TPerlRegEx;
Dmy, mValue: String;
mStart, mLength: Integer;
begin
Memo2.Lines.Clear;
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Memo1.Lines.Text);
// RegExp.Options := [preMultiLine];
if RegExp.Match then
repeat
mValue := UnicodeString(RegExp.MatchedText);
mStart := RegExp.MatchedOffset;
mLength := RegExp.MatchedLength;
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for i:=1 to RegExp.GroupCount do
begin
// Group
Memo2.Lines.Add(Format(' Group : [%d]', [i]));
// Value
mValue := UnicodeString(RegExp.Groups[i]);
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := RegExp.GroupOffsets[i];
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := RegExp.GroupLengths[i];
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
until (not RegExp.MatchAgain);
finally
RegExp.Free;
end
end;
|
コアクラスは UTF-8 で処理しているので、キャストしないと警告が出ます。また、マッチ開始位置やマッチ長は UTF-8 ベースなので、SelStart や SelLength に直接使う事はできません。TSkRegExp と違い、グループ結果からグループ名を取得する事はできません。
|
グループをループ変数で回して取得していますが、もちろん名前付きグループで取得する事も可能です。
ラッパークラス版
Memo1 に入力された文字列中に一致する日付文字列があれば Memo2 に情報を列挙。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
i: Integer;
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
gName: String;
begin
Memo2.Lines.Clear;
//for Match in TRegEx.Matches(Memo1.Lines.Text, Exp, [roMultiLine]) do
for Match in TRegEx.Matches(Memo1.Lines.Text, Exp) do
begin
mValue := Match.Value; // or Match.Groups.Item[0].Value
mStart := Match.Index; // or Match.Groups.Item[0].Index
mLength := Match.Length; // or Match.Groups.Item[0].Length
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for i:=1 to Match.Groups.Count-1 do
begin
// Group
// gName := Match.Groups.Item[i].GroupName; // SkRegExp only
gName := '';
Memo2.Lines.Add(Format(' Group : ''%s'' [%d]', [gName, i]));
// Value
mValue := Match.Groups.Item[i].Value;
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := Match.Groups.Item[i].Index;
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := Match.Groups.Item[i].Length;
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
end;
end;
|
for in do を使わないやり方は以下のようになります。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
i, l: Integer;
Collection: TMatchCollection;
Dmy, mValue: String;
mStart, mLength: Integer;
gName: String;
begin
Memo2.Lines.Clear;
//Collection := TRegEx.Matches(Memo1.Lines.Text, Exp, [roMultiLine]);
Collection := TRegEx.Matches(Memo1.Lines.Text, Exp);
for i:=0 to Collection.Count-1 do
begin
mValue := Collection.Item[i].Value; // or Collection.Item[i].Groups.Item[0].Value
mStart := Collection.Item[i].Index; // or Collection.Item[i].Groups.Item[0].Index
mLength := Collection.Item[i].Length; // or Collection.Item[i].Groups.Item[0].Length
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for l:=1 to Collection.Item[i].Groups.Count-1 do
begin
// Group
// gName := Collection.Item[i].Groups.Item[l].GroupName; // SkRegExp only
gName := '';
Memo2.Lines.Add(Format(' Group : ''%s'' [%d]', [gName, l]));
// Value
mValue := Collection.Item[i].Groups.Item[l].Value;
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := Collection.Item[i].Groups.Item[l].Index;
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := Collection.Item[i].Groups.Item[l].Length;
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
end;
end;
|
本来は以下のような記述も可能なハズです (QC#87752 です。XE2 で解決されています。SkRegularExpressions は最新版で動作します)。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
i: Integer;
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
gName: String;
begin
Memo2.Lines.Clear;
//Match := TRegEx.Match(Memo1.Lines.Text, Exp, [roMultiLine]);
Match := TRegEx.Match(Memo1.Lines.Text, Exp);
while Match.Success do
begin
mValue := Match.Value; // or Match.Groups.Item[0].Value
mStart := Match.Index; // or Match.Groups.Item[0].Index
mLength := Match.Length; // or Match.Groups.Item[0].Length
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for i:=1 to Match.Groups.Count-1 do
begin
// Group
// gName := Match.Groups.Item[i].GroupName; // SkRegExp only
gName := '';
Memo2.Lines.Add(Format(' Group : ''%s'' [%d]', [gName, i]));
// Value
mValue := Match.Groups.Item[i].Value;
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := Match.Groups.Item[i].Index;
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := Match.Groups.Item[i].Length;
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
Match := Match.NextMatch;
end;
end;
|
.NET の RegEx の記述方法とは若干異なる事になりますが、TRegEx.Match を直接呼び出さなければ (クラスメソッドの方を使わなければ) QC#87752 を回避できるようです。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Field1>\d{2,4})\/(?<Field2>\d{1,2})\/(?<Field3>\d{1,2})';
var
i: Integer;
RegEx: TRegEx;
Match: TMatch;
Dmy, mValue: String;
mStart, mLength: Integer;
gName: String;
begin
Memo2.Lines.Clear;
//RegEx := TRegEx.Create(Exp, [roMultiLine]);
RegEx := TRegEx.Create(Exp);
Match := RegEx.Match(Memo1.Lines.Text);
while Match.Success do
begin
mValue := Match.Value; // or Match.Groups.Item[0].Value
mStart := Match.Index; // or Match.Groups.Item[0].Index
mLength := Match.Length; // or Match.Groups.Item[0].Length
Dmy := Format('%s (%d, %d)', [mValue, mStart, mLength]);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add(Dmy);
Memo2.Lines.Add('------------------------------');
Memo2.Lines.Add('');
for i:=1 to Match.Groups.Count-1 do
begin
// Group
// gName := Match.Groups.Item[i].GroupName; // SkRegExp only
gName := '';
Memo2.Lines.Add(Format(' Group : ''%s'' [%d]', [gName, i]));
// Value
mValue := Match.Groups.Item[i].Value;
Memo2.Lines.Add(Format(' Value : ''%s''', [mValue]));
// MatchPos
mStart := Match.Groups.Item[i].Index;
Memo2.Lines.Add(Format(' Start : %d', [mStart]));
// MatchLength
mLength := Match.Groups.Item[i].Length;
Memo2.Lines.Add(Format(' Length: %d', [mLength]));
Memo2.Lines.Add('');
end;
Match := Match.NextMatch;
end;
end;
|
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
SkregExp では TGroup に GroupName プロパティが存在するため、コアクラスの時同様にグループ名を取得する事ができます。
PerlRegEx のラッパークラスは UTF-16 ベースなのでコアクラスの時と違い、マッチ開始位置やマッチ長を SelStart や SelLength に使う事ができます。
|
グループをループ変数で回して取得していますが、もちろん名前付きグループで取得する事も可能です。
グループのキャプチャ (捕捉グループ)
正規表現ではグループの繰り返しに一致した箇所をキャプチャ (捕捉グループ) として取り出す事が可能ですが、現時点ではラッパークラスで対応していないので割愛します。将来、ラッパークラスが対応した時に追記したいと思います。
文字列マッチに使うラッパークラスの(静的)メソッドとクラスメソッド
ラッパークラスの IsMatch() や Match() 或いは Matches() メソッドには静的メソッドとクラスメソッドがあり、前者は TRegEx のインスタンスを生成して利用し、後者はインスタンスを生成せずに利用します。
IsMatch() メソッドは以下のようになっています。一致や比較等の単純なマッチに利用します。
// [メソッド]
function IsMatch(const Input: string): Boolean;
function IsMatch(const Input: string; StartPos: Integer): Boolean;
// [クラスメソッド]
function IsMatch(const Input, Pattern: string): Boolean;
function IsMatch(const Input, Pattern: string; Options: TRegExOptions): Boolean;
|
Match() メソッドは以下のようになっています。主に繰り返しのマッチに利用します。
// [メソッド]
function Match(const Input: string): TMatch;
function Match(const Input: string; StartPos: Integer): TMatch;
function Match(const Input: string; StartPos, Length: Integer): TMatch;
// [クラスメソッド]
function Match(const Input, Pattern: string): TMatch;
function Match(const Input, Pattern: string; Options: TRegExOptions): TMatch;
|
Matches() メソッドは以下のようになっています。主に列挙のマッチに利用します。
静的メソッドの場合、正規表現パターンやオプションは TRegEx.Create() で指定します。
SkRegExp と PerlRegEx でラッパークラスに差異はないので、ソースコード中のリンクは DocWiki のものになっています。
文字列の置換
正規表現文字列に一致する文字列を置換します。
関数版
Memo1 に入力されているすべての日付文字列を、今日の日付で置換します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\d{2,4}\/\d{1,2}\/\d{1,2}';
var
Rep: string;
begin
Rep := FormatDateTime('YYYY/MM/DD', Date);
Memo2.Lines.Text := RegReplace(Exp, Memo1.Lines.Text, Rep, []);
end;
|
Memo1 に入力されているすべての日付文字列を、その日付の翌日に置換します。
function TForm1.CalcTomorrow(ARegExp: TSkRegExp): String;
var
s: string;
begin
s := ARegExp.NamedGroup['Date'];
result := FormatDateTime('YYYY/MM/DD', VarToDateTime(s) + 1);
end;
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Date>\d{2,4}\/\d{1,2}\/\d{1,2})';
var
mEVal: TSkRegExpReplaceFunction;
begin
mEVal := CalcTomorrow;
Memo2.Lines.Text := RegReplace(Exp, Memo1.Lines.Text, mEVal, []);
end;
|
マッチ結果を元にした置換文字列を指定する等の複雑な置換の場合には、手続き型 TSkRegExpReplaceFunction を定義して割り当ててやる必要があります。
|
|
コアクラス版
Memo1 に入力されているすべての日付文字列を、今日の日付で置換します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\d{2,4}\/\d{1,2}\/\d{1,2}';
var
RegExp: TSkRegExp;
Rep: string;
begin
Rep := FormatDateTime('YYYY/MM/DD', Date);
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
Memo2.Lines.Text := RegExp.Replace(Memo1.Lines.Text, Rep);
finally
RegExp.Free;
end
end;
|
Memo1 に入力されているすべての日付文字列を、その日付の翌日に置換します。
function TForm1.CalcTomorrow(ARegExp: TSkRegExp): String;
var
s: string;
begin
s := ARegExp.NamedGroup['Date'];
result := FormatDateTime('YYYY/MM/DD', VarToDateTime(s) + 1);
end;
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Date>\d{2,4}\/\d{1,2}\/\d{1,2})';
var
RegExp: TSkRegExp;
mEVal: TSkRegExpReplaceFunction;
begin
RegExp := TSkRegExp.Create;
try
RegExp.Expression := Exp;
mEVal := CalcTomorrow;
Memo2.Lines.Text := RegExp.Replace(Memo1.Lines.Text, mEVal);
finally
RegExp.Free;
end
end;
|
マッチ結果を元にした置換文字列を指定する等の複雑な置換の場合には、手続き型 TSkRegExpReplaceFunction を定義して割り当ててやる必要があります。
|
Memo1 に入力されているすべての日付文字列を、今日の日付で置換します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\d{2,4}\/\d{1,2}\/\d{1,2}';
var
RegExp: TPerlRegEx;
Rep: string;
begin
Rep := FormatDateTime('YYYY/MM/DD', Date);
RegExp := TPerlRegEx.Create;
try
RegExp.Subject := UTF8String(Memo1.Lines.Text);
RegExp.RegEx := UTF8String(Exp);
RegExp.Replacement := UTF8String(Rep);
RegExp.ReplaceAll;
Memo2.Lines.Text := UnicodeString(RegExp.Subject);
finally
RegExp.Free;
end
end;
|
Memo1 に入力されているすべての日付文字列を、その日付の翌日に置換します。
procedure TForm1.RegExReplace(Sender: TObject; var ReplaceWith: UTF8String);
var
Index: Integer;
s: String;
begin
Index := (Sender as TPerlRegEx).NamedGroup(UTF8String('Date'));
s := UnicodeString((Sender as TPerlRegEx).Groups[Index]);
s := FormatDateTime('YYYY/MM/DD', VarToDateTime(s) + 1);
ReplaceWith := UTF8String(s);
end;
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Date>\d{2,4}\/\d{1,2}\/\d{1,2})';
var
RegExp: TPerlRegEx;
begin
RegExp := TPerlRegEx.Create;
try
RegExp.OnReplace := RegExReplace;
RegExp.Subject := UTF8String(Memo1.Lines.Text);
RegExp.RegEx := UTF8String(Exp);
RegExp.ReplaceAll;
Memo2.Lines.Text := UnicodeString(RegExp.Subject);
finally
RegExp.Free;
end
end;
|
マッチ結果を元にした置換文字列を指定する等の複雑な置換の場合には、イベントハンドラ TPerlRegEx.OnReplace を記述する必要があります。
コアクラスは UTF-8 で処理しているので、キャストしないと警告が出ます。
|
ラッパークラス版
Memo1 に入力されているすべての日付文字列を、今日の日付で置換します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\d{2,4}\/\d{1,2}\/\d{1,2}';
var
Rep: string;
begin
Rep := FormatDateTime('YYYY/MM/DD', Date);
Memo2.Lines.Text := TRegEx.Replace(Memo1.Lines.Text, Exp, Rep, []);
end;
|
Memo1 に入力されているすべての日付文字列を、その日付の翌日に置換します。
function TForm1.CalcTomorrow(const AMatch: TMatch): String;
var
s: string;
begin
s := AMatch.Groups.Item['Date'].Value;
result := FormatDateTime('YYYY/MM/DD', VarToDateTime(s) + 1);
end;
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '(?<Date>\d{2,4}\/\d{1,2}\/\d{1,2})';
var
mEVal: TMatchEvaluator;
begin
mEVal := CalcTomorrow;
Memo2.Lines.Text := TRegEx.Replace(Memo1.Lines.Text, Exp, mEVal, []);
end;
|
マッチ結果を元にした置換文字列を指定する等の複雑な置換の場合には、手続き型 TMatchEvaluator を定義して割り当ててやる必要があります。
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
文字列置換に使うラッパークラスの(静的)メソッドとクラスメソッド
ラッパークラスの Replace() メソッドには静的メソッドとクラスメソッドがあり、前者は TRegEx のインスタンスを生成して利用し、後者はインスタンスを生成せずに利用します。
// [メソッド]
function Replace(const Input, Replacement: string): string;
function Replace(const Input: string; Evaluator: TMatchEvaluator): string;
function Replace(const Input, Replacement: string; Count: Integer): string;
function Replace(const Input: string; Evaluator: TMatchEvaluator; Count: Integer): string;
// [クラスメソッド]
function Replace(const Input, Pattern, Replacement: string): string;
function Replace(const Input, Pattern: string; Evaluator: TMatchEvaluator): string;
function Replace(const Input, Pattern, Replacement: string; Options: TRegExOptions): string;
function Replace(const Input, Pattern: string; Evaluator: TMatchEvaluator; Options: TRegExOptions): string;
|
静的メソッドの場合、正規表現パターンやオプションは TRegEx.Create() で指定します。
SkRegExp と PerlRegEx でラッパークラスに差異はないので、ソースコード中のリンクは DocWiki のものになっています。
文字列の分割
正規表現文字列に一致する文字列で分割します。
関数版
Edit1 に入力されているフルパス名をパス区切り文字で分割し、Memo2 に返します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
sStrings: TStringList;
begin
sStrings := TstringList.Create;
try
RegSplit(Exp, Edit1.Text, sStrings, []);
Memo2.Lines.Text := sStrings.Text;
finally
sStrings.Free;
end;
end;
|
|
|
コアクラス版
Edit1 に入力されているフルパス名をパス区切り文字で分割し、Memo2 に返します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
RegExp: TSkRegExp;
sStrings: TStringList;
begin
RegExp := TSkRegExp.Create;
sStrings := TstringList.Create;
try
RegExp.Expression := Exp;
RegExp.Options := [];
RegExp.Split(Edit1.Text, sStrings);
Memo2.Lines.Text := sStrings.Text;
finally
sStrings.Free;
RegExp.Free;
end
end;
|
|
Edit1 に入力されているフルパス名をパス区切り文字で分割し、Memo2 に返します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
RegExp: TPerlRegEx;
sStrings: TStringList;
begin
RegExp := TPerlRegEx.Create;
sStrings := TstringList.Create;
try
RegExp.Subject := UTF8String(Edit1.Text);
RegExp.RegEx := UTF8String(Exp);
RegExp.Split(sStrings, 0);
Memo2.Lines.Text := sStrings.Text;
finally
sStrings.Free;
RegExp.Free;
end
end;
|
コアクラスは UTF-8 で処理しているので、キャストしないと警告が出ます。
|
ラッパークラス版
この Split() メソッドだけは戻り値の型に違いがあるため、若干記述方法が異なる事に注意が必要です。
Edit1 に入力されているフルパス名をパス区切り文字で分割し、Memo2 に返します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
s: String;
sStrArr: SkRegularExpressions.TStringDynArray; // SkregExp
begin
Memo2.Lines.Clear;
sStrArr := TRegEx.Split(Edit1.Text, Exp, []);
for s in sStrArr do
Memo2.Lines.Add(s);
end;
|
|
Edit1 に入力されているフルパス名をパス区切り文字で分割し、Memo2 に返します。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
s: String;
sStrArr: TArray<string>; // PerlRegEx
begin
Memo2.Lines.Clear;
sStrArr := TRegEx.Split(Edit1.Text, Exp, []);
for s in sStrArr do
Memo2.Lines.Add(s);
end;
|
|
両者を限りなく近い記述にする事は可能です。
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
s: String;
sStrArr: SkRegularExpressions.TStringDynArray;
begin
Memo2.Lines.Clear;
sStrArr :=
SkRegularExpressions.TStringDynArray(TRegEx.Split(Edit1.Text, Exp, []));
for s in sStrArr do
Memo2.Lines.Add(s);
end;
|
|
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
s: String;
sStrArr: Types.TStringDynArray;
begin
Memo2.Lines.Clear;
sStrArr :=
Types.TStringDynArray(TRegEx.Split(Edit1.Text, Exp, []));
for s in sStrArr do
Memo2.Lines.Add(s);
end;
|
|
uses の順序を工夫すれば名前空間の指定を省略できるため、記述を全く同じにする事ができます...が、却ってコードが冗長になるので、コードの同一性に固執しないほうがいいと思います。
文字列分割に使うラッパークラスの(静的)メソッドとクラスメソッド
ラッパークラスの Split() メソッドには静的メソッドとクラスメソッドがあり、前者は TRegEx のインスタンスを生成して利用し、後者はインスタンスを生成せずに利用します。
RegularExpressions では、分割文字列の格納用にジェネリック配列が使われています。
// [メソッド]
function Split(const Input: string): TArray<string>;
function Split(const Input: string; Count: Integer): TArray<string>;
function Split(const Input: string; Count, StartPos: Integer): TArray<string>;
// [クラスメソッド]
function Split(const Input, Pattern: string): TArray<string>;
function Split(const Input, Pattern: string; Options: TRegExOptions): TArray<string>;
|
SkRegularExpressions では、分割文字列の格納用に TStringDynArray (array of string) が使われています。裏を返せば、ジェネリクスが使えない Delphi XE 以前の環境でも同一コードで Split() を動作させる事ができるという事です。
静的メソッドの場合、正規表現パターンやオプションは TRegEx.Create() で指定します。
ソースコード中のリンクは DocWiki のものになっています。
TStringDynArray に関する注意事項
Types 名前空間の TStringDynArray は
TStringDynArray = array of string;
TWideStringDynArray = array of WideString;
|
このように定義されているので、ANSI 版 Delphi では AnsiString、Unicode 版 Delphi では UnicodeString という事になります。
...ですが、SkRegularExpressions 名前空間で定義されている TStringDynArray は、
{$IFDEF UNICODE}
...
REString = UnicodeString;
{$ELSE}
...
REString = WideString;
{$ENDIF}
TStringDynArray = array of REString;
|
こう定義されており、ANSI 版 Delphi だろうが Unicode 版 Delphi だろうが、エレメント幅は 16bit となります。
Unicode 版 Delphi に於いては、
procedure TForm1.Button1Click(Sender: TObject);
const
Exp = '\\';
var
s: String;
sStrArr: Types.TStringDynArray;
begin
Memo2.Lines.Clear;
sStrArr := Types.TStringDynArray(TRegEx.Split(Edit1.Text, Exp, []));
for s in sStrArr do
Memo2.Lines.Add(s);
end;
|
このような "SkRegularExpressions.TStringDynArray -> Types.TStringDynArray" のキャストが可能ですが、ANSI 版 Delphi では "array of WideString -> array of AnsiString" となってしまうので不可能です。
混乱しないようにするためには、SkRegularExpressions.TStringDynArray の方を利用するようにし、単に TStringDynArray とするのではなく、SkRegularExpressions.TStringDynArray のように名前空間を明示的に指定する事をオススメします。
文字列を正規表現形式にエスケープする
例えば、"(ABC)" という文字列を検索したい場合には、正規表現形式では "\(ABC\)" としなければなりません。エスケープ機能は、このように、文字列中にエスケープしなければならない文字を正規表現形式でエスケープしてくれます。
使い所が解りにくいかもしれませんが、普通の文字列検索をやりたい場合でも検索エンジンとして正規表現クラスを使いたい場合に重宝します。普通の文字列での検索/正規表現での検索と使い分けなくて済みますので。
...ただ、実際問題としては検索エンジンを2つ用意せざるを得ない事が多いと思います。何故なら正規表現はその構造上、逆順の検索が苦手だからです。正規表現文字列によっては正順での検索と逆順での検索の場合にマッチ文字列が一致しない事があるため、正規表現での逆順検索ができないアプリケーションも多いです (一旦、正順ですべてを検索し、前後に移動できるものはありますが)。
関数版
Edit1 に入力された文字が '(ABC)' だったらマッチ (正規表現形式だと '\(ABC\)' でなくてはならない事に注意)。
procedure TForm1.Button1Click(Sender: TObject);
var
Exp: String;
Input: String;
begin
Exp := EncodeEscape(Edit1.Text);
Input := '(ABC)';
if RegIsMatch(Exp, Input, []) then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
|
|
コアクラス版
Edit1 に入力された文字が '(ABC)' だったらマッチ。
procedure TfrmMain.Button1Click(Sender: TObject);
var
Exp: String;
Input: String;
begin
Exp := TSkRegExp.EncodeEscape(Edit1.Text);
Input := '(ABC)';
if RegIsMatch(Exp, Input, []) then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
EncodeEscape() はクラスメソッドです。
procedure TfrmMain.Button1Click(Sender: TObject);
var
Exp: String;
Input: String;
begin
Exp := TSkRegExp.EscapeRegExChars(Edit1.Text);
Input := '(ABC)';
if RegIsMatch(Exp, Input, []) then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
ver 2.3.0 からは EncodeEscape() の代わりに EscapeRegExChars() を使うことができます。TPerlRegEx の EscapeRegExChars() と互換性があります。
|
Edit1 に入力された文字が '(ABC)' だったらマッチ。
procedure TForm1.Button1Click(Sender: TObject);
var
Exp: String;
Input: String;
RegExp: TPerlRegEx;
begin
Exp := TPerlRegEx.EscapeRegExChars(Edit1.Text);
Input := '(ABC)';
RegExp := TPerlRegEx.Create;
try
RegExp.RegEx := UTF8String(Exp);
RegExp.Subject := UTF8String(Input);
if RegExp.Match then
ShowMessage('Match.')
else
ShowMessage('No match.');
finally
RegExp.Free;
end;
end;
|
EscapeRegExChars() はクラスメソッドです。コアクラスは UTF-8 で処理しているので、キャストしないと警告が出ます。
|
ラッパークラス版
Edit1 に入力された文字が '(ABC)' だったらマッチ。
procedure TForm1.Button1Click(Sender: TObject);
var
Exp: String;
Input: String;
begin
Exp := TRegEx.Escape(Edit1.Text);
Input := '(ABC)';
if TRegEx.IsMatch(Input, Exp, []) then
ShowMessage('Match.')
else
ShowMessage('No match.');
end;
|
指定する正規表現の方言以外に違いはなく、コードは同一となります。名前空間として SkRegularExpressions と RegularExpressions のどちらを使うかだけの違いです。
|
※ SkRegExp / PerlRegEx はいずれもコアクラスとラッパークラスでエスケープ処理に互換性がありません。SkRegExpW.EncodeEscape <> (TSkRegExp.EscapeRegExChars = TPerlRegEx.EscapeRegExChars) <> (SkRegularExpressions.TRegEx.Escape = RegularExpressions.TRegEx.Escape) です。エスケープ処理を統一したいのであれば、ラッパークラスの TRegEx.Escape() を使うようにしてください。
正規表現形式から通常文字列へアンエスケープする
これこそ使い所が解らない機能です (^^;A
正規表現形式の文字列を 可能な限り 通常の文字列へ変換してくれますが、正規表現にはグループ指定や繰り返し指定があるので、"通常の文字列" に正確に戻すのは不可能だと思えるからです。
多くの正規表現クラスでは Escape() の逆を行う Unescape() が実装されているのですが、現時点ではラッパークラスで対応していないので割愛します...ただ、RegularExpressions のコアクラスである PerlRegEx に実装されていないので、将来に於いても実装される可能性は低いと思います (SkRegExp には DecodeEscape という名前で実装されています)。
SkRegExp ver 2.x への対応
SkRegExp ver 2.x では一部のプロパティが変更になっており、ここで紹介したソースコードの一部がコンパイルできません。
TSkRegExp.Match[n] |
TSkRegExp.Groups[n].Strings |
TSkRegExp.MatchPos[n] |
TSkRegExp.Groups[n].Index |
TSkRegExp.MatchLen[n] |
TSkRegExp.Groups[n].Length |
この表を元にソースコードを読み替えてください。ラッパークラスである SkregularExpressions を使う限りではこの差異を意識する必要はありません。
リンク
正規表現関係のリンクを挙げておきます。
SkRegExp も PerlRegEx も正規表現自体のルーツは Perl にありますから、文法などは Perl 周辺をあたってみるといいでしょう...書籍も豊富に揃ってると思います。ラッパークラスは .NET の正規表現クラスを模してあるので、.NET の資料が役に立つと思います。
Delphi で正規表現を利用する際には .NET 互換ラッパークラスを使えば "いいとこ取りで資料には困らない" んですよね、実は。
| |