示例:字符串搜索
代码:
unit uStringExpression;
interface
uses
SysUtils, Classes, Contnrs, Dialogs;
type
TRegularExpression = class;
TRegularExpressionVisitor = class;
{文字流}
TStream1 = class
private
FData: string;
FPosition: Integer;
public
constructor Create(AData: string);
//---
function Copy: TStream1;
{读入文字,推进输入流}
function NextAvailable(ASize: integer): string;
procedure Next(const AStep: integer = 1);
function Eof: boolean;
//---
property Data: string read FData;
property Position: Integer read FPosition;
end;
{流状态列表}
TState = class(TObjectList)
private
function GetStream(Index: integer): TStream1;
public
constructor Create;
destructor Destroy; override;
//---
procedure Add(AStream: TStream1);
procedure AddAll(AState: TState);
function Copy: TState;
//---
property Stream[Index: integer]: TStream1 read GetStream; default;
end;
TNode1 = class
public
function asRExp: TRegularExpression; virtual; abstract;
end;
TString1 = class(TNode1)
private
FLiterals: string;
public
constructor Create(const ALiterals: string);
//---
function Size: integer;
function Equal(const ALiterals: string): Boolean;
//---
{'&'运算}
function Sequence(ANode: TNode1): TRegularExpression;
{'*'运算}
function Repetition: TRegularExpression;
{'|'运算}
function Alternation(ANode: TNode1): TRegularExpression;
//---
function asRExp: TRegularExpression; override;
end;
{表达式}
TRegularExpression = class(TNode1)
public
function Accept(const AVisitor: TRegularExpressionVisitor): TState; virtual;
abstract;
//---
{'&'运算}
function Sequence(ANode: TNode1): TRegularExpression;
{'*'运算}
function Repetition: TRegularExpression;
{'|'运算}
function Alternation(ANode: TNode1): TRegularExpression;
//---
function asRExp: TRegularExpression; override;
end;
{字符常量}
TLiteralExpression = class(TRegularExpression)
private
FComponents: TString1;
public
constructor Create(AComponents: TString1);
destructor Destroy; override;
//---
function Accept(const AVisitor: TRegularExpressionVisitor): TState; override;
//---
property Components: TString1 read FComponents;
end;
{'|'运算}
TAlternationExpression = class(TRegularExpression)
private
FAlternative1: TRegularExpression;
FAlternative2: TRegularExpression;
public
constructor Create(Alternative1, Alternative2: TRegularExpression);
destructor Destroy; override;
//---
function Accept(const AVisitor: TRegularExpressionVisitor): TState; override;
//---
property Alternative1: TRegularExpression read FAlternative1;
property Alternative2: TRegularExpression read FAlternative2;
end;
{'*'运算}
TRepetitionExpression = class(TRegularExpression)
private
FRepetition: TRegularExpression;
public
constructor Create(ARepetition: TRegularExpression);
destructor Destroy; override;
//---
function Accept(const AVisitor: TRegularExpressionVisitor): TState; override;
//---
property Repetition1: TRegularExpression read FRepetition;
end;
{'&'运算}
TSequenceExpression = class(TRegularExpression)
private
FExpression1: TRegularExpression;
FExpression2: TRegularExpression;
public
constructor Create(AExpression1, AExpression2: TRegularExpression);
destructor Destroy; override;
//---
function Accept(const AVisitor: TRegularExpressionVisitor): TState; override;
//---
property Expression1: TRegularExpression read FExpression1;
property Expression2: TRegularExpression read FExpression2;
end;
{表达式访问者}
TRegularExpressionVisitor = class
public
function VisitSequence(const ASequenceExp: TSequenceExpression): TState; virtual; abstract;
function VisitRepeat(const ARepeatExp: TRepetitionExpression): TState; virtual; abstract;
function VisitAlternation(const AAlternateExp: TAlternationExpression): TState; virtual; abstract;
function VisitLiteral(const ALiteralExp: TLiteralExpression): TState; virtual;
abstract;
end;
TREMatchingVisitor = class(TRegularExpressionVisitor)
private
FInputState: TState;
public
constructor Create(AInputState: TState);
//---
function VisitAlternation(const AAlternateExp: TAlternationExpression): TState;
override;
function VisitLiteral(const ALiteralExp: TLiteralExpression): TState; override;
function VisitRepeat(const ARepeatExp: TRepetitionExpression): TState;
override;
function VisitSequence(const ASequenceExp: TSequenceExpression): TState;
override;
end;
procedure Test;
procedure Test2(ALines:TStrings);
implementation
var
FTempStates: TObjectList;
procedure Test;
{正则表达式: ( ( 'dog' | 'cat' ) repeat & 'weather') }
var
AExpression: TRegularExpression;
AInState, AOutState: TState;
AVisitor: TREMatchingVisitor;
begin
AExpression := TString1.Create('dog').Alternation(TString1.Create('cat')).Repetition.Sequence(TString1.Create('weather'));
try
AInState := TState.Create;
try
AInState.Add(TStream1.Create('dog dog cat weather'));
//---
AVisitor := TREMatchingVisitor.Create(AInState);
try
AOutState := AExpression.Accept(AVisitor);
if AOutState.Count > 0 then
ShowMessage('字符串匹配')
else
ShowMessage('字符串不匹配');
AOutState.Free;
finally
AVisitor.Free;
end;
finally
AInState.Free;
end;
finally
AExpression.Free;
end;
end;
procedure Test2(ALines:TStrings);
{正则表达式: ( ( 'dog' | 'cat' ) repeat & 'weather') }
var
AExpression: TRegularExpression;
AInStream: TStream1;
AStartPosition,AEndPosition: integer;
//---
function _FindString(AInStream: TStream1): integer;
var
AInState,AOutState: TState;
AVisitor: TREMatchingVisitor;
begin
AInState := TState.Create;
try
AInState.Add(AInStream.Copy);
//---
AVisitor := TREMatchingVisitor.Create(AInState);
try
AOutState := AExpression.Accept(AVisitor);
if AOutState.Count > 0 then
Result := AOutState[0].Position
else
Result := 0;
AOutState.Free;
finally
AVisitor.Free;
end;
finally
AInState.Free;
end;
end;
begin
AExpression := TString1.Create('dog').Alternation(TString1.Create('cat')).Repetition.Sequence(TString1.Create('weather'));
try
AInStream := TStream1.Create('12345 dog dog cat weather 12345 cat weather 12345 dog weather cat weather');
try
ALines.Clear;
//---
with AInStream do
begin
while not Eof do
begin
AStartPosition := Position;
AEndPosition := _FindString(AInStream);
if AEndPosition > 0 then
begin
ALines.Add(format('起始位置:%.2d 内容:%s', [AStartPosition,System.Copy(Data,AStartPosition,AEndPosition - AStartPosition + 1)]));
Next(AEndPosition - AStartPosition + 1);
end
else
Next;
end;
end;
finally
AInStream.Free;
end;
finally
AExpression.Free;
end;
end;
function TLiteralExpression.Accept(
const AVisitor: TRegularExpressionVisitor): TState;
begin
Result := AVisitor.VisitLiteral(Self);
end;
constructor TLiteralExpression.Create(AComponents: TString1);
begin
FComponents := AComponents;
end;
destructor TLiteralExpression.Destroy;
begin
FComponents.Free;
//---
inherited;
end;
{ TSequenceExpression }
constructor TSequenceExpression.Create(AExpression1, AExpression2:
TRegularExpression);
begin
FExpression1 := AExpression1;
FExpression2 := AExpression2;
end;
destructor TSequenceExpression.Destroy;
begin
FExpression1.Free;
FExpression2.Free;
//---
inherited;
end;
function TSequenceExpression.Accept(const AVisitor: TRegularExpressionVisitor):
TState;
begin
Result := AVisitor.VisitSequence(Self);
end;
{ TAlternationExpression }
function TAlternationExpression.Accept(
const AVisitor: TRegularExpressionVisitor): TState;
begin
Result := AVisitor.VisitAlternation(Self);
end;
constructor TAlternationExpression.Create(Alternative1, Alternative2:
TRegularExpression);
begin
FAlternative1 := Alternative1;
FAlternative2 := Alternative2;
end;
destructor TAlternationExpression.Destroy;
begin
FAlternative1.Free;
FAlternative2.Free;
//---
inherited;
end;
{ TRepetitionExpression }
function TRepetitionExpression.Accept(
const AVisitor: TRegularExpressionVisitor): TState;
begin
Result := AVisitor.VisitRepeat(self);
end;
constructor TRepetitionExpression.Create(ARepetition: TRegularExpression);
begin
FRepetition := ARepetition;
end;
destructor TRepetitionExpression.Destroy;
begin
FRepetition.Free;
//---
inherited;
end;
constructor TStream1.Create(AData: string);
begin
FData := AData;
FPosition := 1;
end;
function TStream1.Copy: TStream1;
begin
Result := TStream1.Create(FData);
Result.FPosition := self.FPosition;
end;
function TStream1.NextAvailable(ASize: integer): string;
//---去掉空白字符
procedure _SkipBlanks;
begin
while FPosition <= Length(FData) do
begin
if FData[FPosition] = ' ' then
inc(FPosition)
else
break;
end;
end;
begin
_SkipBlanks;
//---
if FPosition + ASize - 1 > Length(FData) then
Result := ''
else
begin
Result := System.Copy(FData, FPosition, ASize);
FPosition := FPosition + ASize;
end;
end;
{ TState }
procedure TState.Add(AStream: TStream1);
begin
inherited Add(AStream);
end;
procedure TState.AddAll(AState: TState);
var
i: Integer;
begin
with AState do
begin
for i := 0 to Count - 1 do
self.Add(Stream[i].Copy);
end;
end;
function TState.Copy: TState;
begin
Result := TState.Create;
Result.AddAll(self);
end;
constructor TState.Create;
begin
inherited;
//---
FTempStates.Add(self);
end;
destructor TState.Destroy;
begin
if not FTempStates.OwnsObjects then
FTempStates.Remove(self);
//---
inherited;
end;
function TState.GetStream(Index: integer): TStream1;
begin
Result := TStream1(Items[Index]);
end;
function TRegularExpression.Sequence(ANode: TNode1): TRegularExpression;
begin
Result := TSequenceExpression.Create(self, ANode.asRExp);
end;
function TRegularExpression.Repetition: TRegularExpression;
begin
Result := TRepetitionExpression.Create(self);
end;
function TRegularExpression.Alternation(ANode: TNode1): TRegularExpression;
begin
Result := TAlternationExpression.Create(self, ANode.asRExp);
end;
function TRegularExpression.asRExp: TRegularExpression;
begin
Result := self;
end;
constructor TString1.Create(const ALiterals: string);
begin
FLiterals := ALiterals;
end;
function TString1.Alternation(ANode: TNode1): TRegularExpression;
begin
Result := TAlternationExpression.Create(self.asRExp, ANode.asRExp);
end;
function TString1.asRExp: TRegularExpression;
begin
Result := TLiteralExpression.Create(self);
end;
function TString1.Size: integer;
begin
Result := Length(FLiterals);
end;
function TString1.Equal(const ALiterals: string): Boolean;
begin
Result := FLiterals = ALiterals;
end;
function TString1.Repetition: TRegularExpression;
begin
Result := TRepetitionExpression.Create(self.asRExp);
end;
function TString1.Sequence(ANode: TNode1): TRegularExpression;
begin
Result := TSequenceExpression.Create(self.asRExp, ANode.asRExp);
end;
procedure TStream1.Next(const AStep: integer = 1);
begin
FPosition := FPosition + AStep;
end;
function TStream1.Eof: boolean;
begin
Result := FPosition > Length(FData);
end;
constructor TREMatchingVisitor.Create(AInputState: TState);
begin
FInputState := AInputState;
end;
function TREMatchingVisitor.VisitAlternation(const AAlternateExp:
TAlternationExpression): TState;
var
AOriginalState, AFinalState: TState;
begin
AOriginalState := FInputState;
AFinalState := AAlternateExp.Alternative1.Accept(Self);
//---
FInputState := AOriginalState;
AFinalState.AddAll(AAlternateExp.Alternative2.Accept(Self));
//---
Result := AFinalState;
end;
function TREMatchingVisitor.VisitLiteral(const ALiteralExp:
TLiteralExpression): TState;
var
AFinalState: TState;
AStream: TStream1;
i: Integer;
begin
AFinalState := TState.Create;
//---
with FInputState do
begin
for i := 0 to Count - 1 do
begin
AStream := Stream[i].Copy;
if ALiteralExp.Components.Equal(AStream.NextAvailable(ALiteralExp.Components.Size)) then
AFinalState.Add(AStream)
else
AStream.Free;
end;
end;
//---
Result := AFinalState;
end;
function TREMatchingVisitor.VisitRepeat(const ARepeatExp:
TRepetitionExpression): TState;
var
AFinalState: TState;
begin
AFinalState := FInputState.Copy;
while FInputState.Count > 0 do
begin
FInputState := ARepeatExp.Repetition1.Accept(self);
AFinalState.AddAll(FInputState);
end;
//---
Result := AFinalState;
end;
function TREMatchingVisitor.VisitSequence(const ASequenceExp:
TSequenceExpression): TState;
begin
FInputState := ASequenceExp.Expression1.Accept(self);
Result := ASequenceExp.Expression2.Accept(self);
end;
initialization
FTempStates := TObjectList.Create;
FTempStates.OwnsObjects := false;
finalization
FTempStates.OwnsObjects := true;
FTempStates.Free;
end.