mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-30 06:08:53 +02:00
423 lines
13 KiB
ObjectPascal
423 lines
13 KiB
ObjectPascal
unit utcregexapi;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{ $DEFINE USEWIDESTRING}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, fpcunit, testutils, testregistry, system.regularexpressionscore, system.regularexpressions;
|
|
|
|
type
|
|
|
|
{ TTestRegExpCore }
|
|
|
|
TTestRegExp = class(TTestCase)
|
|
private
|
|
FRegex: TRegEx;
|
|
function DoReplacer(const Match: TMatch): TREString;
|
|
Protected
|
|
Property Regex : TRegEx Read FRegex Write FRegex;
|
|
Public
|
|
Procedure SetUp; override;
|
|
Procedure TearDown; override;
|
|
Published
|
|
Procedure TestIsMatch;
|
|
Procedure TestIsMatchStartPos;
|
|
Procedure TestClassIsMatch;
|
|
Procedure TestClassIsMatchOptions;
|
|
Procedure TestEscape;
|
|
Procedure TestMatch;
|
|
Procedure TestMatchNoMatch;
|
|
Procedure TestMatchStartPos;
|
|
Procedure TestMatchStartPosLength;
|
|
Procedure TestClassMatch;
|
|
Procedure TestClassMatchOptions;
|
|
Procedure TestMatches;
|
|
Procedure TestMatchesStartPos;
|
|
Procedure TestClassMatches;
|
|
Procedure TestClassMatchesOptions;
|
|
Procedure TestReplace;
|
|
Procedure TestReplaceEval;
|
|
Procedure TestReplaceCount;
|
|
Procedure TestReplaceEvalCount;
|
|
Procedure TestClassReplace;
|
|
Procedure TestClassReplaceEval;
|
|
Procedure TestClassReplaceOptions;
|
|
Procedure TestClassReplaceEvalOptions;
|
|
{
|
|
|
|
|
|
function Split(const aInput: TREString): TREStringDynArray; overload; inline;
|
|
function Split(const aInput: TREString; aCount: Integer): TREStringDynArray; overload; inline;
|
|
function Split(const aInput: TREString; aCount, aStartPos: Integer): TREStringDynArray; overload;
|
|
class function Split(const aInput, aPattern: TREString): TREStringDynArray; overload; static;
|
|
class function Split(const aInput, aPattern: TREString; aOptions: TRegExOptions): TREStringDynArray; overload; static;
|
|
}
|
|
end;
|
|
|
|
implementation
|
|
|
|
Const
|
|
TestStr = 'xyz abba abbba abbbba zyx';
|
|
TestExpr = 'a(b*)a';
|
|
|
|
{ TTestRegExpr}
|
|
|
|
procedure TTestRegExp.SetUp;
|
|
begin
|
|
inherited SetUp;
|
|
FRegex:=Default(TRegex);
|
|
end;
|
|
|
|
procedure TTestRegExp.TearDown;
|
|
begin
|
|
FRegex:=Default(TRegex);
|
|
inherited TearDown;
|
|
end;
|
|
|
|
procedure TTestRegExp.TestIsMatch;
|
|
begin
|
|
// function IsMatch(const aInput: TREString): Boolean; overload;
|
|
Regex:=TRegex.Create(TestExpr);
|
|
AssertTrue('Correct match',Regex.IsMatch(TestStr));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestIsMatchStartPos;
|
|
begin
|
|
// function IsMatch(const aInput: TREString; aStartPos: Integer): Boolean; overload;
|
|
Regex:=TRegex.Create(TestExpr);
|
|
AssertTrue('Correct match',Regex.IsMatch(TestStr,Pos('abbba',TestStr)));
|
|
AssertFalse('No match match at pos',Regex.IsMatch(TestStr,Pos('zyx',TestStr)));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassIsMatch;
|
|
begin
|
|
// class function IsMatch(const aInput, aPattern: TREString): Boolean;overload; static;
|
|
AssertTrue('Correct match',TRegex.IsMatch(TestStr,TestExpr));
|
|
AssertFalse('No match',TRegex.IsMatch(TestStr,TestExpr+'xyz'));
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassIsMatchOptions;
|
|
begin
|
|
// class function IsMatch(const aInput, aPattern: TREString; aOptions: TRegExOptions): Boolean; overload; static;
|
|
AssertTrue('Correct match',TRegex.IsMatch(UpperCase(TestStr),TestExpr,[roIgnoreCase]));
|
|
AssertFalse('No match',TRegex.IsMatch(UpperCase(TestStr),TestExpr+'xyz',[roIgnoreCase]));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestEscape;
|
|
begin
|
|
// class function Escape(const aString: TREString; aUseWildCards: Boolean = False): TREString; static;
|
|
AssertEquals('Wildcard ?','(.)',TRegex.Escape('?',True));
|
|
AssertEquals('Wildcard ?','\?',TRegex.Escape('??',True));
|
|
AssertEquals('Wildcard *','(.*)',TRegex.Escape('*',True));
|
|
AssertEquals('Wildcard ?','\*',TRegex.Escape('**',True));
|
|
AssertEquals('CRLF','\r\n',TRegex.Escape(#13#10,True));
|
|
end;
|
|
|
|
Procedure DumpMatch(M : TMatch);
|
|
|
|
var
|
|
I : Integer;
|
|
|
|
begin
|
|
Writeln('Match value: ',M.Value);
|
|
Writeln('Match index: ',M.Index);
|
|
Writeln('Match length: ',M.Length);
|
|
Writeln('Match group count: ',M.Groups.Count);
|
|
for I:=0 to M.Groups.Count-1 do
|
|
begin
|
|
Writeln('Group ',I);
|
|
Writeln(Format('Match group %d value: ',[i]),M.Groups[i].Value);
|
|
Writeln(Format('Match group %d index: ',[i]),M.Groups[i].Index);
|
|
Writeln(Format('Match group %d length: ',[i]),M.Groups[i].Length);
|
|
end;
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatch;
|
|
|
|
var
|
|
M : TMatch;
|
|
|
|
begin
|
|
// function Match(const aInput: TREString): TMatch; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
M:=RegEx.Match(TestStr);
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abba',M.Value);
|
|
AssertEquals('Match 0 index: ',5,M.Index);
|
|
AssertEquals('Match 0 length: ',4,M.Length);
|
|
AssertEquals('Match 0 group count: ',2,M.Groups.Count);
|
|
AssertEquals('Match 0 group 0 value: ','abba',M.Groups[0].Value);
|
|
AssertEquals('Match 0 group 0 index: ',5,M.Groups[0].Index);
|
|
AssertEquals('Match 0 group 0 length: ',4,M.Groups[0].Length);
|
|
AssertEquals('Match 0 group 1 value: ','bb',M.Groups[1].Value);
|
|
AssertEquals('Match 0 group 1 index: ',6,M.Groups[1].Index);
|
|
AssertEquals('Match 0 group 1 length: ',2,M.Groups[1].Length);
|
|
M:=M.NextMatch;
|
|
AssertTrue('Match 1 result: ',M.Success);
|
|
AssertEquals('Match 1 value: ','abbba',M.Value);
|
|
AssertEquals('Match 1 index: ',10,M.Index);
|
|
AssertEquals('Match 1 length: ',5,M.Length);
|
|
M:=M.NextMatch;
|
|
AssertTrue('Match 2 result: ',M.Success);
|
|
AssertEquals('Match 2 value: ','abbbba',M.Value);
|
|
AssertEquals('Match 2 index: ',16,M.Index);
|
|
AssertEquals('Match 2 length: ',6,M.Length);
|
|
M:=M.NextMatch;
|
|
AssertFalse('Match 3 value: ',M.Success);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatchNoMatch;
|
|
|
|
var
|
|
M : TMatch;
|
|
|
|
begin
|
|
RegEx:=TRegex.Create(TestExpr+'xyz');
|
|
M:=RegEx.Match(TestStr);
|
|
AssertFalse('Success',M.Success);
|
|
AssertEquals('No match value','',M.Value);
|
|
AssertEquals('No match Index',0,M.Index);
|
|
AssertEquals('No match legth',0,M.Length);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatchStartPos;
|
|
|
|
var
|
|
M : TMatch;
|
|
P : Integer;
|
|
|
|
begin
|
|
// function Match(const aInput: TREString): TMatch; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
P:=Pos('abbba',TestStr);
|
|
M:=RegEx.Match(TestStr,P);
|
|
// DumpMatch(M);
|
|
AssertTrue('Match value: ',M.Success);
|
|
AssertEquals('Match value: ','abbba',M.Value);
|
|
AssertEquals('Match index: ',10,M.Index);
|
|
AssertEquals('Match length: ',5,M.Length);
|
|
AssertEquals('Match group count: ',2,M.Groups.Count);
|
|
AssertEquals('Match group 0 value: ','abbba',M.Groups[0].Value);
|
|
AssertEquals('Match group 0 index: ',10,M.Groups[0].Index);
|
|
AssertEquals('Match group 0 length: ',5,M.Groups[0].Length);
|
|
AssertEquals('Match group 1 value: ','bbb',M.Groups[1].Value);
|
|
AssertEquals('Match group 1 index: ',11,M.Groups[1].Index);
|
|
AssertEquals('Match group 1 length: ',3,M.Groups[1].Length);
|
|
M:=M.NextMatch;
|
|
AssertTrue('Match value: ',M.Success);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatchStartPosLength;
|
|
var
|
|
M : TMatch;
|
|
P : Integer;
|
|
|
|
begin
|
|
// function Match(const aInput: TREString): TMatch; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
P:=Pos('abbba',TestStr);
|
|
M:=RegEx.Match(TestStr,P,5);
|
|
// DumpMatch(M);
|
|
AssertTrue('Match value: ',M.Success);
|
|
AssertEquals('Match value: ','abbba',M.Value);
|
|
AssertEquals('Match index: ',10,M.Index);
|
|
AssertEquals('Match length: ',5,M.Length);
|
|
M:=M.NextMatch;
|
|
AssertFalse('No more matches: ',M.Success);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassMatch;
|
|
|
|
var
|
|
M : TMatch;
|
|
|
|
begin
|
|
// class function Match(const aInput, aPattern: TREString): TMatch; overload; static;
|
|
M:=TRegex.Match(TestStr,TestExpr);
|
|
AssertTrue('Match result: ',M.Success);
|
|
AssertEquals('Match value: ','abba',M.Value);
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassMatchOptions;
|
|
|
|
// class function Match(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatch; overload; static;
|
|
var
|
|
M : TMatch;
|
|
|
|
begin
|
|
// class function Match(const aInput, aPattern: TREString): TMatch; overload; static;
|
|
M:=TRegex.Match(UpperCase(TestStr),TestExpr,[roIgnoreCase]);
|
|
AssertTrue('Match result: ',M.Success);
|
|
AssertEquals('Match value: ','ABBA',M.Value);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatches;
|
|
|
|
var
|
|
MS : TMatchCollection;
|
|
M,M2 : TMatch;
|
|
|
|
begin
|
|
// function Matches(const aInput: TREString): TMatchCollection; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
MS:=RegEx.Matches(TestStr);
|
|
AssertEquals('Match count',3,MS.Count);
|
|
M:=MS[0];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abba',M.Value);
|
|
AssertEquals('Match 0 index: ',5,M.Index);
|
|
AssertEquals('Match 0 length: ',4,M.Length);
|
|
AssertEquals('Match 0 group count: ',2,M.Groups.Count);
|
|
AssertEquals('Match 0 group 0 value: ','abba',M.Groups[0].Value);
|
|
AssertEquals('Match 0 group 0 index: ',5,M.Groups[0].Index);
|
|
AssertEquals('Match 0 group 0 length: ',4,M.Groups[0].Length);
|
|
AssertEquals('Match 0 group 1 value: ','bb',M.Groups[1].Value);
|
|
AssertEquals('Match 0 group 1 index: ',6,M.Groups[1].Index);
|
|
AssertEquals('Match 0 group 1 length: ',2,M.Groups[1].Length);
|
|
M2:=M.NextMatch;
|
|
M:=MS[1];
|
|
AssertTrue('Match 1 resul: ',M.Success);
|
|
AssertEquals('Match 1 value: ','abbba',M.Value);
|
|
AssertEquals('NextMatch value: ','abbba',M2.Value);
|
|
AssertEquals('Match 1 index: ',10,M.Index);
|
|
AssertEquals('Match 1 length: ',5,M.Length);
|
|
M:=MS[2];
|
|
AssertTrue('Match 2 result: ',M.Success);
|
|
AssertEquals('Match 2 value: ','abbbba',M.Value);
|
|
AssertEquals('Match 2 index: ',16,M.Index);
|
|
AssertEquals('Match 2 length: ',6,M.Length);
|
|
M:=M.NextMatch;
|
|
AssertFalse('Match value: ',M.Success);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestMatchesStartPos;
|
|
var
|
|
MS : TMatchCollection;
|
|
M : TMatch;
|
|
|
|
begin
|
|
// function Matches(const aInput: TREString; aStartPos: Integer): TMatchCollection; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
MS:=RegEx.Matches(TestStr,9);
|
|
AssertEquals('Match count',2,MS.Count);
|
|
M:=MS[0];
|
|
AssertTrue('Match 1 resul: ',M.Success);
|
|
AssertEquals('Match 1 value: ','abbba',M.Value);
|
|
M:=MS[1];
|
|
AssertTrue('Match 1 resul: ',M.Success);
|
|
AssertEquals('Match 1 value: ','abbbba',M.Value);
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassMatches;
|
|
var
|
|
MS : TMatchCollection;
|
|
M : TMatch;
|
|
begin
|
|
// class function Matches(const aInput, aPattern: TREString): TMatchCollection; overload; static;
|
|
MS:=TRegEx.Matches(TestStr,TestExpr);
|
|
AssertEquals('Match count',3,MS.Count);
|
|
M:=MS[0];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abba',M.Value);
|
|
M:=MS[1];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abbba',M.Value);
|
|
M:=MS[2];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abbbba',M.Value);
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassMatchesOptions;
|
|
|
|
|
|
var
|
|
MS : TMatchCollection;
|
|
M : TMatch;
|
|
begin
|
|
// class function Matches(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatchCollection; overload; static;
|
|
MS:=TRegEx.Matches(TestStr,UpperCase(TestExpr),[roIgnoreCase]);
|
|
AssertEquals('Match count',3,MS.Count);
|
|
M:=MS[0];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abba',M.Value);
|
|
M:=MS[1];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abbba',M.Value);
|
|
M:=MS[2];
|
|
AssertTrue('Match 0 result: ',M.Success);
|
|
AssertEquals('Match 0 value: ','abbbba',M.Value);
|
|
end;
|
|
|
|
procedure TTestRegExp.TestReplace;
|
|
begin
|
|
// function Replace(const aInput, aReplacement: TREString): TREString; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
AssertEquals('Result','xyz c c c zyx',RegEx.Replace(TestStr,'c'));
|
|
end;
|
|
|
|
function TTestRegExp.DoReplacer(const Match: TMatch): TREString;
|
|
|
|
begin
|
|
Result:='<'+Match.Value+'>';
|
|
// Writeln('Replace "',Match.Value,'" -> "',Result,'"')
|
|
end;
|
|
|
|
procedure TTestRegExp.TestReplaceEval;
|
|
begin
|
|
// function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator): TREString; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',RegEx.Replace(TestStr,@DoReplacer));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestReplaceCount;
|
|
begin
|
|
// function Replace(const aInput, aReplacement: TREString; aCount: Integer): TREString; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
AssertEquals('Result','xyz c c abbbba zyx',RegEx.Replace(TestStr,'c',2));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestReplaceEvalCount;
|
|
begin
|
|
// function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator; aCount: Integer): TREString; overload;
|
|
RegEx:=TRegex.Create(TestExpr);
|
|
AssertEquals('Result','xyz <abba> <abbba> abbbba zyx',RegEx.Replace(TestStr,@DoReplacer,2));
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassReplace;
|
|
begin
|
|
// class function Replace(const aInput, aPattern, aReplacement: TREString): TREString; overload; static;
|
|
AssertEquals('Result','xyz c c c zyx',TRegEx.Replace(TestStr,TestExpr,'c'));
|
|
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassReplaceEval;
|
|
begin
|
|
// class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator): TREString; overload; static;
|
|
AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',TRegEx.Replace(TestStr,TestExpr,@DoReplacer));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassReplaceOptions;
|
|
begin
|
|
// class function Replace(const aInput, aPattern, aReplacement: TREString; aOptions: TRegExOptions): TREString; overload; static;
|
|
AssertEquals('Result','xyz c c c zyx',TRegEx.Replace(TestStr,UpperCase(TestExpr),'c',[roIgnoreCase]));
|
|
end;
|
|
|
|
procedure TTestRegExp.TestClassReplaceEvalOptions;
|
|
begin
|
|
// class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator; aOptions: TRegExOptions): TREString; overload; static;
|
|
AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',TRegEx.Replace(TestStr,UpperCase(TestExpr),@DoReplacer,[roIgnoreCase]));
|
|
|
|
end;
|
|
|
|
initialization
|
|
RegisterTest(TTestRegExp);
|
|
end.
|
|
|