Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Parsen von Seitenzahlen (https://www.delphipraxis.net/137353-parsen-von-seitenzahlen.html)

Sir Rufo 18. Aug 2012 15:39

AW: Parsen von Seitenzahlen
 
Zitat:

Zitat von Furtbichler (Beitrag 1178698)
Zitat:

Zitat von Sir Rufo (Beitrag 1178681)
Wäre es nicht wesentlich schicker dieses mit dem State-Pattern zu lösen?

Schicker vielleicht, aber nicht unbedingt lesbarer und ein klein wenig Overkill.

Aber wesentlich angenehmer, wenn es um die Erweiterbarkeit geht.
Hier der Ansatz mit dem State-Pattern:
Delphi-Quellcode:
unit PageStrParser;

interface

{$DEFINE UseStateInstanceCache }

uses
  Classes
{$IFDEF UseStateInstanceCache}
    , Generics.Collections
{$ENDIF};

type
  TPageStrParser          = class;
  TPageStrParserStateClass = class of TPageStrParserState;

  TPageStrParserState = class
  private
    FParser : TPageStrParser;
    procedure ChangeState( NewState : TPageStrParserStateClass );
    procedure AddCharToCurrPage1( Ch : Char );
    procedure AddCharToCurrPage2( Ch : Char );
    procedure AddCurrPagesToList;
  public
    constructor Create( AParser : TPageStrParser );

    procedure ProcessChar( Ch : Char; Pos : Integer ); virtual; abstract;
  end;

  TPageStrParser = class
  private
    FState : TPageStrParserState;
{$IFDEF UseStateInstanceCache}
    FStateCache : TDictionary<TPageStrParserStateClass, TPageStrParserState>;
{$ENDIF}
    FCurrPageFrom : string;
    FCurrPageTo :  string;
    FPageList :    TStrings;
    function GetState : TPageStrParserStateClass;
    procedure SetState( const Value : TPageStrParserStateClass );
  protected
    procedure AddCharToCurrPage1( Ch : Char );
    procedure AddCharToCurrPage2( Ch : Char );
    procedure AddCurrPagesToList;

    property State : TPageStrParserStateClass read GetState write SetState;
  public
    constructor Create;
    destructor Destroy; override;

    procedure ExtractPages( const s : string; const aPageList : TStrings );
  end;

implementation

uses
  SysUtils;

type
  TPageStrParserPageFromStartState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserPageFromState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserPageFromEndState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserPageToStartState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserPageToState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserPageToEndState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

  TPageStrParserErrorState = class( TPageStrParserState )
  public
    procedure ProcessChar( Ch : Char; Pos : Integer ); override;
  end;

resourcestring
  EParserError = 'Error in line at position %d: Invalid or Unexpected Char "%s"';

  { TPageStrParser }

procedure TPageStrParser.AddCharToCurrPage1( Ch : Char );
begin
  FCurrPageFrom := FCurrPageFrom + Ch;
end;

procedure TPageStrParser.AddCharToCurrPage2( Ch : Char );
begin
  FCurrPageTo := FCurrPageTo + Ch;
end;

procedure TPageStrParser.AddCurrPagesToList;
var
  lFrom, lTo : Integer;
  lPage :     Integer;
  lPageNr :   string;
begin
  lFrom := StrToInt( FCurrPageFrom );
  lTo  := StrToIntDef( FCurrPageTo, lFrom );

  if lFrom <= lTo
  then
    for lPage := lFrom to lTo do
      begin
        lPageNr := IntToStr( lPage );
        FPageList.Add( lPageNr );
      end
  else
    for lPage := lFrom downto lTo do
      begin
        lPageNr := IntToStr( lPage );
        FPageList.Add( lPageNr );
      end;

  FCurrPageFrom := '';
  FCurrPageTo  := '';
end;

constructor TPageStrParser.Create;
begin
  inherited;
{$IFDEF UseStateInstanceCache}
  FStateCache := TObjectDictionary<TPageStrParserStateClass, TPageStrParserState>.Create( [doOwnsValues] );
{$ENDIF}
end;

destructor TPageStrParser.Destroy;
begin
{$IFDEF UseStateInstanceCache}
  FStateCache.Free;
{$ELSE}
  FState.Free;
{$ENDIF}
  inherited;
end;

procedure TPageStrParser.ExtractPages( const s : string; const aPageList : TStrings );
var
  i : Integer;
  Ch : Char;
begin
  FPageList := aPageList;

  FPageList.BeginUpdate;
  try
    FPageList.Clear;

    State := TPageStrParserPageFromStartState;

    FCurrPageFrom := '';
    FCurrPageTo  := '';

    for i := 1 to Length( s ) do
      begin
        Ch := s[i];
        FState.ProcessChar( Ch, i );

        if State = TPageStrParserErrorState
        then
          FState.ProcessChar( Ch, i );

      end;

    if FCurrPageFrom <> ''
    then
      AddCurrPagesToList;

  finally
    FPageList.EndUpdate;
  end;
end;

function TPageStrParser.GetState : TPageStrParserStateClass;
begin
  Result := TPageStrParserStateClass( FState.ClassType );
end;

procedure TPageStrParser.SetState( const Value : TPageStrParserStateClass );
begin
{$IFDEF UseStateInstanceCache}
  if FStateCache.ContainsKey( Value )
  then
    FState := FStateCache.Items[Value]
  else
    begin
      FState := Value.Create( Self );
      FStateCache.Add( Value, FState );
    end;
{$ELSE}
  FState.Free;
  FState := Value.Create( Self );
{$ENDIF}
end;

{ TPageStrParserState }

procedure TPageStrParserState.AddCharToCurrPage1( Ch : Char );
begin
  FParser.AddCharToCurrPage1( Ch );
end;

procedure TPageStrParserState.AddCharToCurrPage2( Ch : Char );
begin
  FParser.AddCharToCurrPage2( Ch );
end;

procedure TPageStrParserState.AddCurrPagesToList;
begin
  FParser.AddCurrPagesToList;
end;

procedure TPageStrParserState.ChangeState( NewState : TPageStrParserStateClass );
begin
  FParser.State := NewState;
end;

constructor TPageStrParserState.Create( AParser : TPageStrParser );
begin
  inherited Create;
  FParser := AParser;
end;

{ TPageStrParserErrorState }

procedure TPageStrParserErrorState.ProcessChar( Ch : Char; Pos : Integer );
begin
  raise Exception.Create( Format( EParserError, [Pos, Ch] ) );
end;

{ TPageStrParserPageFromStartState }

procedure TPageStrParserPageFromStartState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ;
    '0' .. '9' :
      begin
        AddCharToCurrPage1( Ch );
        ChangeState( TPageStrParserPageFromState );
      end;
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

{ TPageStrParserPageFromState }

procedure TPageStrParserPageFromState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ChangeState( TPageStrParserPageFromEndState );
    '0' .. '9' :
      begin
        AddCharToCurrPage1( Ch );
      end;
    '-' :
      begin
        ChangeState( TPageStrParserPageToStartState );
      end;
    ';', ',' :
      begin
        AddCurrPagesToList;
        ChangeState( TPageStrParserPageFromStartState );
      end;
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

{ TPageStrParserPageFromEndState }

procedure TPageStrParserPageFromEndState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ;
    '-' :
      ChangeState( TPageStrParserPageToStartState );
    ',', ';' :
      begin
        AddCurrPagesToList;
        ChangeState( TPageStrParserPageFromStartState );
      end
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

{ TPageStrParserPageToStartState }

procedure TPageStrParserPageToStartState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ;
    '0' .. '9' :
      begin
        AddCharToCurrPage2( Ch );
        ChangeState( TPageStrParserPageToState );
      end;
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

{ TPageStrParserPageToState }

procedure TPageStrParserPageToState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ChangeState( TPageStrParserPageToEndState );
    '0' .. '9' :
      begin
        AddCharToCurrPage2( Ch );
      end;
    ';', ',' :
      begin
        AddCurrPagesToList;
        ChangeState( TPageStrParserPageFromStartState );
      end;
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

{ TPageStrParserPageToEndState }

procedure TPageStrParserPageToEndState.ProcessChar( Ch : Char; Pos : Integer );
begin
  case Ch of
    ' ' :
      ;
    ',', ';' :
      begin
        AddCurrPagesToList;
        ChangeState( TPageStrParserPageFromStartState );
      end
  else
    ChangeState( TPageStrParserErrorState );
  end;
end;

end.

Furtbichler 18. Aug 2012 15:49

AW: Parsen von Seitenzahlen
 
:shock:

Und was willst Du erweitern? Lass uns doch mal checken, ob das wirklich erweiterbarer ist. Gib mal was vor? :mrgreen:

Sir Rufo 18. Aug 2012 15:54

AW: Parsen von Seitenzahlen
 
Zitat:

Zitat von Furtbichler (Beitrag 1178713)
:shock:

Und was willst Du erweitern? Lass uns doch mal checken, ob das wirklich erweiterbarer ist. Gib mal was vor? :mrgreen:

Das weiß ich ja noch nicht, sonst wäre ich ja Hellseher, wenn ich wüßte, wie die Anforderung in x Tagen sich ändern :mrgreen:

Furtbichler 18. Aug 2012 17:01

AW: Parsen von Seitenzahlen
 
Na, ich wüsste schon so Einiges. Deshalb bin ich ein erfahrener Entwickler ;-) Lässt sich alles mit den 10-Zeilern hier erledigen.

Aber ich gehe mal davon aus, das Du deinen Code nicht als minimalistisch-kompaktes Beispiel hier eingestellt hast, das dieses Piddy-Problem realitätsnah umsetzt.

Dein Beispiel taugt aber durchaus als gutes Beispiel, denn im Kleinen soll man üben was einem im Großen gelingen soll.

Früher hieß das 'State-Pattern' übrigens DEA, und daran hatte ich auch gedacht, es aber verworfen, weil die Syntax einfach zu simpel ist und es fürs Parsen von Strings nun wirklich Standardlösungen gibt (aka RegEx).

Aber egal. Viele Wege führen nach Rom.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:29 Uhr.
Seite 3 von 3     123   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz