《GOF设计模式》—解释器 (INTERPRETER)—Delphi源码示例:字符串搜索

示例:字符串搜索
说明:
    搜索匹配一个模式的字符串是一个常见问题。正则表达式是描述字符串模式的一种标准语言。与其为每一个正则表达式都构造一个特定的算法,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合。

(1)、文法
    正则表达式用下列文法定义:
expression ::= literal | alternation | sequence | repetition | '(' expression ')'
alternation ::= expression '|' expression
sequence ::= expression '&' expression
repetition ::= expression 'repeat'
literal ::= 'a' | 'b' | 'c'| …… {'a' | 'b' | 'c' | ……}*

(2)、表示:文法元素对象。
clip_image002


(3)、解释器
    Match操作实现了一个正则表达式的一个解释器。定义抽象语法树的每一个类都实现了这一操作。
clip_image002[6]
(4)、句子
    例如:正则表达式"( ( 'dog' | 'cat' ) repeat &'weather')"匹配输入字符串"dog dog cat weather"。

代码:
 
unit uStringExpression;

interface

uses
    Classes,Contnrs;

type
    {文字流}
    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;

    TRegularExpression = class;

    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 Match(AInputState: TState): 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 Match(AInputState: TState): TState; override;
    end;
    {'|'运算}
    TAlternationExpression = class(TRegularExpression)
    private
        FAlternative1: TRegularExpression;
        FAlternative2: TRegularExpression;
    public
        constructor Create(Alternative1,Alternative2: TRegularExpression);
        destructor Destroy; override;
        //---
        function Match(AInputState: TState): TState; override;
    end;
    {'*'运算}
    TRepetitionExpression = class(TRegularExpression)
    private
        FRepetition: TRegularExpression;
    public
        constructor Create(ARepetition: TRegularExpression);
        destructor Destroy; override;
        //---
        function Match(AInputState: TState): TState; override;
    end;
    {'&'运算}
    TSequenceExpression = class(TRegularExpression)
    private
        FExpression1: TRegularExpression;
        FExpression2: TRegularExpression;
    public
        constructor Create(AExpression1,AExpression2: TRegularExpression);
        destructor Destroy; override;
        //---
        function Match(AInputState: TState): TState; override;
    end;

implementation

var
    FTempStates: TObjectList;

constructor TLiteralExpression.Create(AComponents: TString1);
begin
    FComponents := AComponents;
end;

destructor TLiteralExpression.Destroy;
begin
    FComponents.Free;
    //---
    inherited;
end;

function TLiteralExpression.Match(AInputState: TState): TState;
var
    AFinalState: TState;
    AStream: TStream1;
    i: Integer;
begin
    AFinalState := TState.Create;
    //---
    with AInputState do
    begin
        for i := 0 to Count - 1 do
        begin
            AStream := Stream[i].Copy;
            if FComponents.Equal(AStream.NextAvailable(FComponents.Size)) then
                AFinalState.Add(AStream)
            else
                AStream.Free;
        end;
    end;
    //---
    Result := AFinalState;
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.Match(AInputState: TState): TState;
begin
    Result := FExpression2.Match(FExpression1.Match(AInputState));
end;

{ TAlternationExpression }

constructor TAlternationExpression.Create(Alternative1,Alternative2:
    TRegularExpression);
begin
    FAlternative1 := Alternative1;
    FAlternative2 := Alternative2;
end;

destructor TAlternationExpression.Destroy;
begin
    FAlternative1.Free;
    FAlternative2.Free;
    //---
    inherited;
end;

function TAlternationExpression.Match(AInputState: TState): TState;
var
    AFinalState: TState;
begin
    AFinalState := FAlternative1.Match(AInputState);
    AFinalState.AddAll(FAlternative2.Match(AInputState));
    //---
    Result := AFinalState;
end;

{ TRepetitionExpression }

constructor TRepetitionExpression.Create(ARepetition: TRegularExpression);
begin
    FRepetition := ARepetition;
end;

destructor TRepetitionExpression.Destroy;
begin
    FRepetition.Free;
    //---
    inherited;
end;

function TRepetitionExpression.Match(AInputState: TState): TState;
var
    AState,AFinalState: TState;
begin
    AState := AInputState;
    AFinalState := AInputState.Copy;
    while AState.Count > 0 do
    begin
        AState := FRepetition.Match(aState);
        AFinalState.AddAll(aState);
    end;
    //---
    Result := AFinalState;
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;

initialization
    FTempStates := TObjectList.Create;
    FTempStates.OwnsObjects := false;

finalization
    FTempStates.OwnsObjects := true;
    FTempStates.Free;

end.

procedure TForm1.Button1Click(Sender: TObject);
{正则表达式: ( ( 'dog' | 'cat' ) repeat & 'weather')  }
var
    AExpression: TRegularExpression;
    AInState,AOutState: TState;
begin
    Memo1.Clear;
    //---
    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'));
            //---
            AOutState := AExpression.Match(AInState);
            if AOutState.Count > 0 then
                Memo1.Text := '字符串匹配';
            AOutState.Free;
        finally
            AInState.Free;
        end;
    finally
        AExpression.Free;
    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
{正则表达式: ( ( 'dog' | 'cat' ) repeat & 'weather')  }
var
    AExpression: TRegularExpression;
    AInStream: TStream1;
    AStartPosition,AEndPosition: integer;
    //---
    function _FindString(AInStream: TStream1): integer;
    var
        AInState,AOutState: TState;
    begin
        AInState := TState.Create;
        try
            AInState.Add(AInStream.Copy);
            //---
            AOutState := AExpression.Match(AInState);
            if AOutState.Count > 0 then
                Result := AOutState[0].Position
            else
                Result := 0;
            AOutState.Free;
        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
            Memo1.Clear;
            //---
            with AInStream do
            begin
                while not Eof do
                begin
                    AStartPosition := Position;
                    AEndPosition := _FindString(AInStream);
                    if AEndPosition > 0 then
                    begin
                        Memo1.Lines.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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值