{********************************************************************} { } { Developer Express Visual Component Library } { ExpressEditors } { } { Copyright (c) 1998-2008 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSEDITORS AND ALL } { ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {********************************************************************} unit cxRegExpr; {$I cxVer.inc} interface uses SysUtils, Classes, cxClasses, cxEdit, cxEditConsts; type { TcxRegExprError } TcxRegExprError = class private FChar: Integer; FLine: Integer; FMessage: string; function GetFullMessage: string; public constructor Create(ALine: Integer; AChar: Integer; AMessage: string); function Clone: TcxRegExprError; property Char: Integer read FChar; property FullMessage: string read GetFullMessage; property Line: Integer read FLine; property Message: string read FMessage; end; { TcxRegExprErrors } TcxRegExprErrors = class private FErrors: TList; function GetCount: Integer; function GetItems(Index: Integer): TcxRegExprError; public constructor Create; destructor Destroy; override; procedure Add(AError: TcxRegExprError); procedure Clear; function Clone: TcxRegExprErrors; property Count: Integer read GetCount; property Items[Index: Integer]: TcxRegExprError read GetItems; default; end; { EcxRegExprError } EcxRegExprError = class(EcxEditError) private FErrors: TcxRegExprErrors; public constructor Create(AErrors: TcxRegExprErrors); property Errors: TcxRegExprErrors read FErrors; end; { TcxLexem } TcxLexem = record Char: Integer; Code: Integer; Line: Integer; Value: string; end; PcxLexem = ^TcxLexem; { TcxRegExprLexemCode } TcxRegExprLexemCode = ( relcSymbol, relcSpecial, relcInteger, relcAll, relcId, relcNotId, relcDigit, relcNotDigit, relcSpace, relcNotSpace, relcReference, relcDateSeparator, relcTimeSeparator ); { TcxLexems } TcxLexems = class private FLexems: TList; function GetCount: Integer; function GetItems(Index: Integer): TcxLexem; public constructor Create; destructor Destroy; override; procedure Add(ALexem: TcxLexem); procedure Clear; property Count: Integer read GetCount; property Items[Index: Integer]: TcxLexem read GetItems; default; end; { TcxRegExprItem } TcxRegExprItem = class public function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; virtual; abstract; function Clone: TcxRegExprItem; virtual; abstract; end; { TcxRegExprSymbol } TcxRegExprSymbol = class(TcxRegExprItem) private FValue: Char; public constructor Create(AValue: Char); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprTimeSeparator } TcxRegExprTimeSeparator = class(TcxRegExprItem) public function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; function Value: Char; end; { TcxRegExprDateSeparator } TcxRegExprDateSeparator = class(TcxRegExprItem) public function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; function Value: Char; end; { TcxRegExprSubrange } TcxRegExprSubrange = class(TcxRegExprItem) private FStartValue: Char; FFinishValue: Char; public constructor Create(AStartValue: Char; AFinishValue: Char); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprEnumeration } TcxRegExprEnumeration = class(TcxRegExprItem) private FInverse: Boolean; public constructor Create(AInverse: Boolean = False); end; { TcxRegExprUserEnumeration } TcxRegExprUserEnumeration = class(TcxRegExprEnumeration) private FItems: TList; function Item(AIndex: Integer): TcxRegExprItem; public constructor Create(AInverse: Boolean = False); destructor Destroy; override; procedure Add(AItem: TcxRegExprItem); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprDigit } TcxRegExprDigit = class(TcxRegExprEnumeration) public constructor Create(AInverse: Boolean = False); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprIdLetter } TcxRegExprIdLetter = class(TcxRegExprEnumeration) public constructor Create(AInverse: Boolean = False); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprSpace } TcxRegExprSpace = class(TcxRegExprEnumeration) public constructor Create(AInverse: Boolean = False); function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; { TcxRegExprAll } TcxRegExprAll = class(TcxRegExprItem) public function Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; override; function Clone: TcxRegExprItem; override; end; TcxRegExprStates = class; { TcxRegExprState } TcxRegExprState = class protected FStates: TcxRegExprStates; public constructor Create; destructor Destroy; override; procedure Add(AState: TcxRegExprState); overload; procedure Add(AStates: TcxRegExprStates); overload; function Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; virtual; function Clone: TcxRegExprState; virtual; function GetAllNextStates: TcxRegExprStates; function GetSelf: TcxRegExprStates; virtual; function Next(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; property States: TcxRegExprStates read FStates; end; { TcxRegExprSimpleState } TcxRegExprSimpleState = class(TcxRegExprState) private FIsFinal: Boolean; FValue: TcxRegExprItem; public constructor Create(AValue: TcxRegExprItem); destructor Destroy; override; function Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; override; function Clone: TcxRegExprState; override; function GetSelf: TcxRegExprStates; override; procedure SetFinal; property IsFinal: Boolean read FIsFinal; end; { TcxRegExprBlockState } TcxRegExprBlockState = class(TcxRegExprState) public function Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; override; function Clone: TcxRegExprState; override; function GetSelf: TcxRegExprStates; override; end; { TcxRegExprStates } TcxRegExprStates = class private FStates: TList; function GetCount: Integer; function GetState(AIndex: Integer): TcxRegExprState; public constructor Create; destructor Destroy; override; procedure Add(AState: TcxRegExprState); overload; procedure Add(AStates: TcxRegExprStates); overload; procedure Clear; function Equ(var ASymbol: Char): Boolean; function GetAllNextStates: TcxRegExprStates; function IsFinal: Boolean; function Next(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; property Count: Integer read GetCount; property State[AIndex: Integer]: TcxRegExprState read GetState; default; end; TcxRegExprParserAlts = class; TcxRegExpr = class; { TcxRegExprAutomat } TcxRegExprAutomat = class private FCurrentStates: TcxRegExprStates; FExpr: TcxRegExprParserAlts; FHistory: TList; FOwner: TcxRegExpr; FStartState: TcxRegExprSimpleState; function GetAllNextStates: TcxRegExprStates; function Pop: TcxRegExprStates; procedure Push(AStates: TcxRegExprStates); public constructor Create(AExpr: TcxRegExprParserAlts; AOwner: TcxRegExpr); destructor Destroy; override; function IsFinal: Boolean; function IsStart: Boolean; function Next(var AToken: Char; ACaseInsensitive: Boolean): Boolean; function Prev: Boolean; function Print: string; procedure Reset; procedure ReUpdate; procedure Update; end; { TcxRegExprQuantifier } TcxRegExprQuantifier = class public function CanMissing: Boolean; virtual; abstract; function CanRepeat: Boolean; virtual; abstract; function Clone: TcxRegExprQuantifier; virtual; abstract; function Print: string; virtual; abstract; end; { TcxRegExprSimpleQuantifier } TcxRegExprSimpleQuantifier = class(TcxRegExprQuantifier) // missing quantifier public function CanMissing: Boolean; override; function CanRepeat: Boolean; override; function Clone: TcxRegExprQuantifier; override; function Print: string; override; end; { TcxRegExprQuestionQuantifier } TcxRegExprQuestionQuantifier = class(TcxRegExprQuantifier) // ? public function CanMissing: Boolean; override; function CanRepeat: Boolean; override; function Clone: TcxRegExprQuantifier; override; function Print: string; override; end; { TcxRegExprStarQuantifier } TcxRegExprStarQuantifier = class(TcxRegExprQuantifier) // * public function CanMissing: Boolean; override; function CanRepeat: Boolean; override; function Clone: TcxRegExprQuantifier; override; function Print: string; override; end; { TcxRegExprPlusQuantifier } TcxRegExprPlusQuantifier = class(TcxRegExprQuantifier) // + public function CanMissing: Boolean; override; function CanRepeat: Boolean; override; function Clone: TcxRegExprQuantifier; override; function Print: string; override; end; { TcxRegExprParserItem } TcxRegExprParserItem = class private FQuantifier: TcxRegExprQuantifier; public constructor Create(AQuantifier: TcxRegExprQuantifier = nil); destructor Destroy; override; function CanEmpty: Boolean; virtual; abstract; function CanMissing: Boolean; function CanRepeat: Boolean; function Clone: TcxRegExprParserItem; virtual; abstract; function NotQuantifier: Boolean; function Print: string; virtual; abstract; procedure SetFinal; virtual; abstract; procedure SetQuantifier(AQuantifier: TcxRegExprQuantifier); end; { TcxRegExprParserSimpleItem } TcxRegExprParserSimpleItem = class(TcxRegExprParserItem) private FState: TcxRegExprState; public constructor Create(AState: TcxRegExprState; AQuantifier: TcxRegExprQuantifier = nil); destructor Destroy; override; function CanEmpty: Boolean; override; function Clone: TcxRegExprParserItem; override; function Print: string; override; procedure SetFinal; override; property State: TcxRegExprState read FState; end; TcxRegExprParserAlt = class; { TcxRegExprParserBlockItem } TcxRegExprParserBlockItem = class(TcxRegExprParserItem) private FAlts: TcxRegExprParserAlts; FFinishState: TcxRegExprState; FStartState: TcxRegExprState; public constructor Create(AQuantifier: TcxRegExprQuantifier = nil); destructor Destroy; override; function CanEmpty: Boolean; override; procedure CreateConnections; procedure AddAlt(AAlt: TcxRegExprParserAlt); procedure AddAlts(AAlts: TcxRegExprParserAlts); function Clone: TcxRegExprParserItem; override; function Print: string; override; procedure SetFinal; override; property Alts: TcxRegExprParserAlts read FAlts; property FinishState: TcxRegExprState read FFinishState; property StartState: TcxRegExprState read FStartState; end; { TcxRegExprParserAlt } TcxRegExprParserAlt = class private FItems: TList; function GetCount: Integer; function GetFirstItem: TcxRegExprParserItem; function GetItem(AIndex: Integer): TcxRegExprParserItem; function GetLastItem: TcxRegExprParserItem; procedure SetLastItem(AItem: TcxRegExprParserItem); public constructor Create; destructor Destroy; override; procedure Add(AItem: TcxRegExprParserItem); function CanEmpty: Boolean; function CanMissing: Boolean; function Clone: TcxRegExprParserAlt; procedure CreateConnections; procedure CreateFinalStates; function GetStartConnections: TcxRegExprStates; function Print: string; procedure SetFinishConnection(AFinishState: TcxRegExprState); property Count: Integer read GetCount; property FirstItem: TcxRegExprParserItem read GetFirstItem; property Item[AIndex: Integer]: TcxRegExprParserItem read GetItem; default; property LastItem: TcxRegExprParserItem read GetLastItem write SetLastItem; end; { TcxRegExprParserAlts } TcxRegExprParserAlts = class private FAlts: TList; function GetAlt(AIndex: Integer): TcxRegExprParserAlt; function GetCount: Integer; function GetLastAlt: TcxRegExprParserAlt; public constructor Create; destructor Destroy; override; procedure Add(AAlt: TcxRegExprParserAlt); procedure AddAlt; function CanEmpty: Boolean; procedure CreateConnections; procedure CreateFinalStates; function Clone: TcxRegExprParserAlts; function GetStartConnections: TcxRegExprStates; function Print: string; procedure SetFinishConnections(AFinishState: TcxRegExprState); function StartStateIsFinal: Boolean; function ThereIsEmptyAlt: Boolean; property Alt[AIndex: Integer]: TcxRegExprParserAlt read GetAlt; default; property Count: Integer read GetCount; property LastAlt: TcxRegExprParserAlt read GetLastAlt; end; TcxSymbolDeleteEvent = procedure of object; TcxSymbolUpdateEvent = procedure(ASymbol: Char) of object; { TcxRegExpr } TcxRegExpr = class private FAutomat: TcxRegExprAutomat; FBlocks: TList; FChar: Integer; FCaseInsensitive: Boolean; FCompiled: Boolean; FErrors: TcxRegExprErrors; FFirstExpr: Boolean; FIndex: Integer; FLexemIndex: Integer; FLexems: TcxLexems; FLine: Integer; FOnSymbolDelete: TcxSymbolDeleteEvent; FOnSymbolUpdate: TcxSymbolUpdateEvent; FStream: TMemoryStream; FUpdateOn: Boolean; procedure Clear; function Decimal(AToken: Char): Boolean; function EmptyStream: Boolean; function CreateLexem(ALine: Integer; AChar: Integer; ACode: Integer; AValue: string): TcxLexem; function GetLexem(var ALexem: TcxLexem): Boolean; function GetToken(out AToken: Char): Boolean; function GetStream: TStream; function Hexadecimal(AToken: Char): Boolean; function LookToken(out AToken: Char; APtr: Integer): Boolean; function ParseAlt(AAlt: TcxRegExprParserAlt; Global: Boolean = True): Boolean; function ParseBlock: TcxRegExprParserBlockItem; function ParseEnumeration: TcxRegExprParserSimpleItem; procedure ParseExpr; procedure ParseQuantifier(var A: Integer; var B: Integer); procedure ScanASCII(ALine: Integer; AChar: Integer); procedure ScanClass; procedure ScanExpr; procedure ScanEscape(ALine: Integer; AChar: Integer); function ScanInteger(ALine: Integer; AChar: Integer; var AToken: Char): Boolean; procedure ScanQuantifier; procedure ScanString; procedure SetUpdateOn(AUpdateOn: Boolean); function Space(AToken: Char): Boolean; procedure SymbolDelete; procedure SymbolUpdate(ASymbol: Char); procedure TestCompiledStatus; public constructor Create; destructor Destroy; override; procedure Compile(AStream: TStream); function IsCompiled: Boolean; function IsFinal: Boolean; function IsStart: Boolean; function Next(var AToken: Char): Boolean; function NextEx(const AString: string): string; function Prev: Boolean; function Print: string; procedure Reset; property CaseInsensitive: Boolean read FCaseInsensitive write FCaseInsensitive; property Stream: TStream read GetStream; property UpdateOn: Boolean read FUpdateOn write SetUpdateOn; property OnSymbolDelete: TcxSymbolDeleteEvent read FOnSymbolDelete write FOnSymbolDelete; property OnSymbolUpdate: TcxSymbolUpdateEvent read FOnSymbolUpdate write FOnSymbolUpdate; end; function IsTextFullValid(const AText, AMask: string): Boolean; function IsTextValid(const AText, AMask: string): Boolean; implementation { TcxRegExprError } constructor TcxRegExprError.Create(ALine, AChar: Integer; AMessage: string); begin inherited Create; FLine := ALine; FChar := AChar; FMessage := AMessage; end; function TcxRegExprError.Clone: TcxRegExprError; begin Result := TcxRegExprError.Create(FLine, FChar, FMessage); end; function TcxRegExprError.GetFullMessage: string; begin Result := ''; if FLine > 0 then begin Result := Result + cxGetResourceString(@scxRegExprLine) + IntToStr(FLine); if FChar > 0 then Result := Result + ', ' + cxGetResourceString(@scxRegExprChar) + IntToStr(FChar); Result := Result + ': '; end; Result := Result + FMessage; end; { TcxRegExprErrors } constructor TcxRegExprErrors.Create; begin inherited Create; FErrors := TList.Create; end; destructor TcxRegExprErrors.Destroy; begin Clear; FErrors.Free; inherited Destroy; end; procedure TcxRegExprErrors.Add(AError: TcxRegExprError); begin FErrors.Add(AError); end; procedure TcxRegExprErrors.Clear; var I: Integer; begin for I := 0 to FErrors.Count - 1 do TcxRegExprError(FErrors[I]).Free; FErrors.Clear; end; function TcxRegExprErrors.Clone: TcxRegExprErrors; var I: Integer; begin Result := TcxRegExprErrors.Create; for I := 0 to Count - 1 do Result.Add(Items[I].Clone); end; function TcxRegExprErrors.GetCount: Integer; begin Result := FErrors.Count; end; function TcxRegExprErrors.GetItems(Index: Integer): TcxRegExprError; begin Result := TcxRegExprError(FErrors[Index]); end; { EcxRegExprError } constructor EcxRegExprError.Create(AErrors: TcxRegExprErrors); begin FErrors := AErrors; end; { TcxLexems } constructor TcxLexems.Create; begin inherited Create; FLexems := TList.Create; end; destructor TcxLexems.Destroy; begin Clear; FLexems.Free; inherited Destroy; end; procedure TcxLexems.Add(ALexem: TcxLexem); var LexemP: PcxLexem; begin New(LexemP); LexemP^ := ALexem; FLexems.Add(LexemP); end; procedure TcxLexems.Clear; var I: Integer; begin for I := 0 to FLexems.Count - 1 do Dispose(PcxLexem(FLexems[I])); FLexems.Clear; end; function TcxLexems.GetCount: Integer; begin Result := FLexems.Count; end; function TcxLexems.GetItems(Index: Integer): TcxLexem; begin Result := PcxLexem(FLexems[Index])^; end; { TcxRegExprSymbol } constructor TcxRegExprSymbol.Create(AValue: Char); begin inherited Create; FValue := AValue; end; function TcxRegExprSymbol.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin if ACaseInsensitive then begin Result := AnsiUpperCase(AToken) = AnsiUpperCase(FValue); if Result then AToken := FValue; end else Result := AToken = FValue; end; function TcxRegExprSymbol.Clone: TcxRegExprItem; begin Result := TcxRegExprSymbol.Create(FValue); end; { TcxRegExprTimeSeparator } function TcxRegExprTimeSeparator.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin Result := AToken = Value; end; function TcxRegExprTimeSeparator.Clone: TcxRegExprItem; begin Result := TcxRegExprTimeSeparator.Create; end; function TcxRegExprTimeSeparator.Value: Char; begin Result := TimeSeparator; end; { TcxRegExprDateSeparator } function TcxRegExprDateSeparator.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin Result := AToken = Value; end; function TcxRegExprDateSeparator.Clone: TcxRegExprItem; begin Result := TcxRegExprDateSeparator.Create; end; function TcxRegExprDateSeparator.Value: Char; begin Result := DateSeparator; end; { TcxRegExprSubrange } constructor TcxRegExprSubrange.Create(AStartValue, AFinishValue: Char); begin inherited Create; FStartValue := AStartValue; FFinishValue := AFinishValue; end; function TcxRegExprSubrange.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin Result := (AToken >= FStartValue) and (AToken <= FFinishValue); end; function TcxRegExprSubrange.Clone: TcxRegExprItem; begin Result := TcxRegExprSubrange.Create(FStartValue, FFinishValue); end; { TcxRegExprEnumeration } constructor TcxRegExprEnumeration.Create(AInverse: Boolean = False); begin inherited Create; FInverse := AInverse; end; { TcxRegExprUserEnumeration } constructor TcxRegExprUserEnumeration.Create(AInverse: Boolean); begin inherited Create(AInverse); FItems := TList.Create; end; destructor TcxRegExprUserEnumeration.Destroy; var I: Integer; begin for I := 0 to FItems.Count - 1 do Item(I).Free; FItems.Free; inherited Destroy; end; procedure TcxRegExprUserEnumeration.Add(AItem: TcxRegExprItem); begin FItems.Add(AItem); end; function TcxRegExprUserEnumeration.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; var I: Integer; begin for I := 0 to FItems.Count - 1 do if Item(I).Check(AToken, ACaseInsensitive) then begin Result := not FInverse; Exit; end; Result := FInverse; end; function TcxRegExprUserEnumeration.Item(AIndex: Integer): TcxRegExprItem; begin Result := TcxRegExprItem(FItems[AIndex]); end; function TcxRegExprUserEnumeration.Clone: TcxRegExprItem; var I: Integer; begin Result := TcxRegExprUserEnumeration.Create(FInverse); for I := 0 to FItems.Count - 1 do TcxRegExprUserEnumeration(Result).Add(Item(I).Clone); end; { TcxRegExprDigit } constructor TcxRegExprDigit.Create(AInverse: Boolean); begin inherited Create(AInverse); end; function TcxRegExprDigit.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin if (AToken >= '0') and (AToken <= '9') then Result := not FInverse else Result := FInverse; end; function TcxRegExprDigit.Clone: TcxRegExprItem; begin Result := TcxRegExprDigit.Create(FInverse); end; { TcxRegExprIdLetter } constructor TcxRegExprIdLetter.Create(AInverse: Boolean); begin inherited Create(AInverse); end; function TcxRegExprIdLetter.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin if ((AToken >= 'a') and (AToken <= 'z')) or (AToken = '_') or ((AToken >= 'A') and (AToken <= 'Z')) or ((AToken >= '0') and (AToken <= '9')) then Result := not FInverse else Result := FInverse; end; function TcxRegExprIdLetter.Clone: TcxRegExprItem; begin Result := TcxRegExprIdLetter.Create(FInverse); end; { TcxRegExprSpace } constructor TcxRegExprSpace.Create(AInverse: Boolean); begin inherited Create(AInverse); end; function TcxRegExprSpace.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin if (AToken = ' ') or (AToken = #0) or (AToken = #9) or (AToken = #10) or (AToken = #12) or (AToken = #13) then Result := not FInverse else Result := FInverse; end; function TcxRegExprSpace.Clone: TcxRegExprItem; begin Result := TcxRegExprSpace.Create(FInverse); end; { TcxRegExprAll } function TcxRegExprAll.Check(var AToken: Char; ACaseInsensitive: Boolean): Boolean; begin Result := True; end; function TcxRegExprAll.Clone: TcxRegExprItem; begin Result := TcxRegExprAll.Create; end; { TcxRegExprState } constructor TcxRegExprState.Create; begin inherited Create; FStates := TcxRegExprStates.Create; end; destructor TcxRegExprState.Destroy; begin FStates.Free; inherited Destroy; end; procedure TcxRegExprState.Add(AState: TcxRegExprState); begin States.Add(AState); end; procedure TcxRegExprState.Add(AStates: TcxRegExprStates); begin States.Add(AStates); end; function TcxRegExprState.Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; begin Result := TcxRegExprStates.Create; end; function TcxRegExprState.Clone: TcxRegExprState; begin Result := TcxRegExprState.Create; end; function TcxRegExprState.GetAllNextStates: TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to States.Count - 1 do Result.Add(States[I].GetSelf); end; function TcxRegExprState.GetSelf: TcxRegExprStates; begin Result := TcxRegExprStates.Create; Result.Add(Self); end; function TcxRegExprState.Next(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to FStates.Count - 1 do Result.Add(FStates[I].Check(AToken, ACaseInsensitive)); end; { TcxRegExprSimpleState } constructor TcxRegExprSimpleState.Create(AValue: TcxRegExprItem); begin inherited Create; FValue := AValue; FIsFinal := False; end; destructor TcxRegExprSimpleState.Destroy; begin if FValue <> nil then FValue.Free; inherited Destroy; end; function TcxRegExprSimpleState.Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; begin Result := TcxRegExprStates.Create; if FValue.Check(AToken, ACaseInsensitive) then Result.Add(Self); end; function TcxRegExprSimpleState.Clone: TcxRegExprState; begin Result := TcxRegExprSimpleState.Create(FValue.Clone); end; function TcxRegExprSimpleState.GetSelf: TcxRegExprStates; begin Result := TcxRegExprStates.Create; Result.Add(Self); end; procedure TcxRegExprSimpleState.SetFinal; begin FIsFinal := True; end; { TcxRegExprBlockState } function TcxRegExprBlockState.Check(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; begin Result := Next(AToken, ACaseInsensitive); end; function TcxRegExprBlockState.Clone: TcxRegExprState; begin Result := TcxRegExprBlockState.Create; end; function TcxRegExprBlockState.GetSelf: TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to States.Count - 1 do Result.Add(States[I].GetSelf); end; { TcxRegExprStates } constructor TcxRegExprStates.Create; begin inherited Create; FStates := TList.Create; end; destructor TcxRegExprStates.Destroy; begin FStates.Free; inherited Destroy; end; procedure TcxRegExprStates.Add(AState: TcxRegExprState); begin FStates.Add(AState); end; procedure TcxRegExprStates.Add(AStates: TcxRegExprStates); var I: Integer; begin for I := 0 to AStates.Count - 1 do Add(AStates.State[I]); AStates.Free; end; procedure TcxRegExprStates.Clear; begin FStates.Clear; end; function TcxRegExprStates.Equ(var ASymbol: Char): Boolean; var I: Integer; Flag: Boolean; begin if Count = 0 then begin Result := False; Exit; end; Flag := False; for I := 0 to Count - 1 do begin if State[I] is TcxRegExprSimpleState then begin with TcxRegExprSimpleState(State[I]) do begin if FValue is TcxRegExprSymbol then begin if not Flag then begin ASymbol := TcxRegExprSymbol(FValue).FValue; Flag := True; end else begin if ASymbol <> TcxRegExprSymbol(FValue).FValue then begin Result := False; Exit; end; end; end else if FValue is TcxRegExprTimeSeparator then begin if not Flag then begin ASymbol := TcxRegExprTimeSeparator(FValue).Value; Flag := True; end else begin if ASymbol <> TcxRegExprTimeSeparator(FValue).Value then begin Result := False; Exit; end; end; end else if FValue is TcxRegExprDateSeparator then begin if not Flag then begin ASymbol := TcxRegExprDateSeparator(FValue).Value; Flag := True; end else begin if ASymbol <> TcxRegExprDateSeparator(FValue).Value then begin Result := False; Exit; end; end; end else begin Result := False; Exit; end; end; end else begin Result := False; Exit; end; end; Result := True; end; function TcxRegExprStates.GetAllNextStates: TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to Count - 1 do Result.Add(State[I].GetAllNextStates); end; function TcxRegExprStates.IsFinal: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if TcxRegExprSimpleState(State[I]).IsFinal then begin Result := True; Exit; end; Result := False; end; function TcxRegExprStates.Next(var AToken: Char; ACaseInsensitive: Boolean): TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to Count - 1 do Result.Add(State[I].Next(AToken, ACaseInsensitive)); end; function TcxRegExprStates.GetCount: Integer; begin Result := FStates.Count; end; function TcxRegExprStates.GetState(AIndex: Integer): TcxRegExprState; begin Result := TcxRegExprState(FStates[AIndex]); end; { TcxRegExprAutomat } constructor TcxRegExprAutomat.Create(AExpr: TcxRegExprParserAlts; AOwner: TcxRegExpr); begin inherited Create; FHistory := TList.Create; FExpr := AExpr; FStartState := TcxRegExprSimpleState.Create(nil); FStartState.Add(FExpr.GetStartConnections); if FExpr.StartStateIsFinal then FStartState.SetFinal; FCurrentStates := TcxRegExprStates.Create; FCurrentStates.Add(FStartState); FOwner := AOwner; end; destructor TcxRegExprAutomat.Destroy; var I: Integer; begin for I := 0 to FHistory.Count - 1 do TcxRegExprStates(FHistory[I]).Free; FHistory.Free; FCurrentStates.Free; FExpr.Free; FStartState.Free; inherited Destroy; end; function TcxRegExprAutomat.GetAllNextStates: TcxRegExprStates; begin Result := FCurrentStates.GetAllNextStates end; function TcxRegExprAutomat.IsFinal: Boolean; begin Result := FCurrentStates.IsFinal; end; function TcxRegExprAutomat.IsStart: Boolean; begin Result := FCurrentStates[0] = FStartState; end; function TcxRegExprAutomat.Next(var AToken: Char; ACaseInsensitive: Boolean): Boolean; var NextStates: TcxRegExprStates; begin NextStates := FCurrentStates.Next(AToken, ACaseInsensitive); if NextStates.Count > 0 then begin Push(FCurrentStates); FCurrentStates := NextStates; Result := True; end else begin NextStates.Free; Result := False; end; end; function TcxRegExprAutomat.Prev: Boolean; var LastStates: TcxRegExprStates; begin LastStates := Pop; if LastStates = nil then Result := False else begin FCurrentStates.Free; FCurrentStates := LastStates; Result := True; end; end; function TcxRegExprAutomat.Print: string; begin Result := FExpr.Print; end; procedure TcxRegExprAutomat.Reset; var I: Integer; begin for I := 0 to FHistory.Count - 1 do TcxRegExprStates(FHistory[I]).Free; FHistory.Clear; FCurrentStates.Free; FCurrentStates := TcxRegExprStates.Create; FCurrentStates.Add(FStartState); end; procedure TcxRegExprAutomat.ReUpdate; var ASymbol: Char; PrevStates: TcxRegExprStates; AllNextStates: TcxRegExprStates; begin while FCurrentStates.Equ(ASymbol) do begin PrevStates := Pop; if PrevStates = nil then begin Push(PrevStates); Exit; end; AllNextStates := PrevStates.GetAllNextStates; if not AllNextStates.Equ(ASymbol) or PrevStates.IsFinal then begin Push(PrevStates); AllNextStates.Free; Exit; end else AllNextStates.Free; FOwner.SymbolDelete; FCurrentStates.Free; FCurrentStates := PrevStates; end; end; procedure TcxRegExprAutomat.Update; var NextStates: TcxRegExprStates; ASymbol: Char; begin if FCurrentStates.IsFinal then Exit; NextStates := GetAllNextStates; while NextStates.Equ(ASymbol) do begin FOwner.SymbolUpdate(ASymbol); Push(FCurrentStates); FCurrentStates := NextStates; if NextStates.IsFinal then Exit; NextStates := GetAllNextStates; end; NextStates.Free; end; function TcxRegExprAutomat.Pop: TcxRegExprStates; begin if FHistory.Count > 0 then begin Result := TcxRegExprStates(FHistory.Last); FHistory.Delete(FHistory.Count - 1); end else Result := nil; end; procedure TcxRegExprAutomat.Push(AStates: TcxRegExprStates); begin FHistory.Add(AStates); end; { TcxRegExprSimpleQuantifier } function TcxRegExprSimpleQuantifier.CanMissing: Boolean; begin Result := False; end; function TcxRegExprSimpleQuantifier.CanRepeat: Boolean; begin Result := False; end; function TcxRegExprSimpleQuantifier.Clone: TcxRegExprQuantifier; begin Result := TcxRegExprSimpleQuantifier.Create; end; function TcxRegExprSimpleQuantifier.Print: string; begin Result := ''; end; { TcxRegExprQuestionQuantifier } function TcxRegExprQuestionQuantifier.CanMissing: Boolean; begin Result := True; end; function TcxRegExprQuestionQuantifier.CanRepeat: Boolean; begin Result := False; end; function TcxRegExprQuestionQuantifier.Clone: TcxRegExprQuantifier; begin Result := TcxRegExprQuestionQuantifier.Create; end; function TcxRegExprQuestionQuantifier.Print: string; begin Result := '?'; end; { TcxRegExprStarQuantifier } function TcxRegExprStarQuantifier.CanMissing: Boolean; begin Result := True; end; function TcxRegExprStarQuantifier.CanRepeat: Boolean; begin Result := True; end; function TcxRegExprStarQuantifier.Clone: TcxRegExprQuantifier; begin Result := TcxRegExprStarQuantifier.Create; end; function TcxRegExprStarQuantifier.Print: string; begin Result := '*'; end; { TcxRegExprPlusQuantifier } function TcxRegExprPlusQuantifier.CanMissing: Boolean; begin Result := False; end; function TcxRegExprPlusQuantifier.CanRepeat: Boolean; begin Result := True; end; function TcxRegExprPlusQuantifier.Clone: TcxRegExprQuantifier; begin Result := TcxRegExprPlusQuantifier.Create; end; function TcxRegExprPlusQuantifier.Print: string; begin Result := '+'; end; { TcxRegExprParserItem } constructor TcxRegExprParserItem.Create(AQuantifier: TcxRegExprQuantifier = nil); begin inherited Create; if AQuantifier = nil then FQuantifier := TcxRegExprSimpleQuantifier.Create else FQuantifier := AQuantifier; end; destructor TcxRegExprParserItem.Destroy; begin FQuantifier.Free; inherited Destroy; end; function TcxRegExprParserItem.CanMissing: Boolean; begin Result := FQuantifier.CanMissing; end; function TcxRegExprParserItem.CanRepeat: Boolean; begin Result := FQuantifier.CanRepeat; end; function TcxRegExprParserItem.NotQuantifier: Boolean; begin Result := FQuantifier is TcxRegExprSimpleQuantifier; end; procedure TcxRegExprParserItem.SetQuantifier( AQuantifier: TcxRegExprQuantifier); begin if AQuantifier <> nil then begin FQuantifier.Free; FQuantifier := AQuantifier; end; end; { TcxRegExprParserSimpleItem } constructor TcxRegExprParserSimpleItem.Create(AState: TcxRegExprState; AQuantifier: TcxRegExprQuantifier); begin inherited Create(AQuantifier); FState := AState; end; destructor TcxRegExprParserSimpleItem.Destroy; begin if FState <> nil then FState.Free; inherited Destroy; end; function TcxRegExprParserSimpleItem.CanEmpty: Boolean; begin Result := FQuantifier.CanMissing; end; function TcxRegExprParserSimpleItem.Clone: TcxRegExprParserItem; begin Result := TcxRegExprParserSimpleItem.Create(FState.Clone, FQuantifier.Clone); end; function TcxRegExprParserSimpleItem.Print: string; begin Result := 'item --> ' + FQuantifier.Print + #13#10; end; procedure TcxRegExprParserSimpleItem.SetFinal; begin TcxRegExprSimpleState(State).SetFinal; end; { TcxRegExprParserBlockItem } constructor TcxRegExprParserBlockItem.Create(AQuantifier: TcxRegExprQuantifier = nil); begin inherited Create(AQuantifier); FStartState := TcxRegExprBlockState.Create; FFinishState := TcxRegExprBlockState.Create; FAlts := TcxRegExprParserAlts.Create; end; destructor TcxRegExprParserBlockItem.Destroy; begin FStartState.Free; FFinishState.Free; FAlts.Free; inherited Destroy; end; function TcxRegExprParserBlockItem.CanEmpty: Boolean; begin if FQuantifier.CanMissing then Result := True else Result := Alts.CanEmpty; end; procedure TcxRegExprParserBlockItem.CreateConnections; begin Alts.CreateConnections; end; procedure TcxRegExprParserBlockItem.AddAlt(AAlt: TcxRegExprParserAlt); begin FAlts.Add(AAlt); end; procedure TcxRegExprParserBlockItem.AddAlts(AAlts: TcxRegExprParserAlts); var I: Integer; begin for I := 0 to AAlts.Count - 1 do FAlts.Add(AAlts[I]); AAlts.Free; end; function TcxRegExprParserBlockItem.Clone: TcxRegExprParserItem; begin Result := TcxRegExprParserBlockItem.Create(FQuantifier.Clone); with TcxRegExprParserBlockItem(Result) do begin FAlts.Free; FAlts := Self.Alts.Clone; end; end; function TcxRegExprParserBlockItem.Print: string; begin Result := ''#13#10; Result := Result + Alts.Print; Result := Result + ' --> ' + FQuantifier.Print + #13#10; end; procedure TcxRegExprParserBlockItem.SetFinal; begin Alts.CreateFinalStates; end; { TcxRegExprParserAlt } constructor TcxRegExprParserAlt.Create; begin inherited Create; FItems := TList.Create; end; destructor TcxRegExprParserAlt.Destroy; var I: Integer; begin for I := 0 to FItems.Count - 1 do TcxRegExprParserItem(FItems[I]).Free; FItems.Free; inherited Destroy; end; procedure TcxRegExprParserAlt.Add(AItem: TcxRegExprParserItem); begin FItems.Add(AItem); end; function TcxRegExprParserAlt.CanEmpty: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if not Item[I].CanEmpty then begin Result := False; Exit; end; Result := True; end; function TcxRegExprParserAlt.CanMissing: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if not Item[I].CanMissing then begin Result := False; Exit; end; Result := True; end; function TcxRegExprParserAlt.Clone: TcxRegExprParserAlt; var I: Integer; begin Result := TcxRegExprParserAlt.Create; for I := 0 to Count - 1 do Result.Add(Item[I].Clone); end; procedure TcxRegExprParserAlt.CreateConnections; var I, J: Integer; begin for I := 0 to Count - 1 do begin if Item[I] is TcxRegExprParserSimpleItem then begin with TcxRegExprParserSimpleItem(Item[I]) do begin for J := I + 1 to Count - 1 do begin if Item[J] is TcxRegExprParserSimpleItem then State.Add(TcxRegExprParserSimpleItem(Item[J]).State) else if Item[J] is TcxRegExprParserBlockItem then State.Add(TcxRegExprParserBlockItem(Item[J]).StartState); if not Item[J].CanMissing then Break; end; if Item[I].CanRepeat then State.Add(State); end; end else if Item[I] is TcxRegExprParserBlockItem then begin with TcxRegExprParserBlockItem(Item[I]) do begin for J := I + 1 to Count - 1 do begin if Item[J] is TcxRegExprParserSimpleItem then FinishState.Add(TcxRegExprParserSimpleItem(Item[J]).State) else if Item[J] is TcxRegExprParserBlockItem then FinishState.Add(TcxRegExprParserBlockItem(Item[J]).StartState); if not Item[J].CanMissing then Break; end; if Item[I].CanRepeat then FinishState.Add(StartState); StartState.Add(Alts.GetStartConnections); if Alts.ThereIsEmptyAlt then StartState.Add(FinishState); Alts.CreateConnections; Alts.SetFinishConnections(FinishState); end; end; end; end; procedure TcxRegExprParserAlt.CreateFinalStates; var I: Integer; begin for I := Count - 1 downto 0 do begin Item[I].SetFinal; if not Item[I].CanMissing then Break; end; end; function TcxRegExprParserAlt.GetStartConnections: TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to Count - 1 do begin if Item[I] is TcxRegExprParserSimpleItem then Result.Add(TcxRegExprParserSimpleItem(Item[I]).State) else if Item[I] is TcxRegExprParserBlockItem then Result.Add(TcxRegExprParserBlockItem(Item[I]).StartState); if not Item[I].CanMissing then Break; end; end; function TcxRegExprParserAlt.Print: string; var I: Integer; begin Result := ''#13#10; for I := 0 to Count - 1 do Result := Result + Item[I].Print; Result := result + ''#13#10; end; procedure TcxRegExprParserAlt.SetFinishConnection( AFinishState: TcxRegExprState); var I: Integer; begin for I := Count - 1 downto 0 do begin if Item[I] is TcxRegExprParserSimpleItem then TcxRegExprParserSimpleItem(Item[I]).State.Add(AFinishState) else if Item[I] is TcxRegExprParserBlockItem then TcxRegExprParserBlockItem(Item[I]).FinishState.Add(AFinishState); if not Item[I].CanMissing then Break; end; end; function TcxRegExprParserAlt.GetCount: Integer; begin Result := FItems.Count; end; function TcxRegExprParserAlt.GetFirstItem: TcxRegExprParserItem; begin Result := TcxRegExprParserItem(FItems[0]); end; function TcxRegExprParserAlt.GetItem( AIndex: Integer): TcxRegExprParserItem; begin Result := TcxRegExprParserItem(FItems[AIndex]); end; function TcxRegExprParserAlt.GetLastItem: TcxRegExprParserItem; begin Result := TcxRegExprParserItem(FItems.Last); end; procedure TcxRegExprParserAlt.SetLastItem(AItem: TcxRegExprParserItem); begin TcxRegExprParserItem(FItems[FItems.Count - 1]).Free; FItems.Delete(FItems.Count - 1); FItems.Add(AItem); end; { TcxRegExprParserAlts } constructor TcxRegExprParserAlts.Create; begin inherited Create; FAlts := TList.Create; end; destructor TcxRegExprParserAlts.Destroy; var I: Integer; begin for I := 0 to Count - 1 do Alt[I].Free; FAlts.Free; inherited Destroy; end; procedure TcxRegExprParserAlts.Add(AAlt: TcxRegExprParserAlt); begin FAlts.Add(AAlt); end; procedure TcxRegExprParserAlts.AddAlt; begin FAlts.Add(TcxRegExprParserAlt.Create) end; function TcxRegExprParserAlts.CanEmpty: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if Alt[I].CanEmpty then begin Result := True; Exit; end; Result := False; end; procedure TcxRegExprParserAlts.CreateConnections; var I: Integer; begin for I := 0 to Count - 1 do Alt[I].CreateConnections; end; procedure TcxRegExprParserAlts.CreateFinalStates; var I: Integer; begin for I := 0 to Count - 1 do Alt[I].CreateFinalStates; end; function TcxRegExprParserAlts.Clone: TcxRegExprParserAlts; var I: Integer; begin Result := TcxRegExprParserAlts.Create; for I := 0 to Count - 1 do Result.Add(Alt[I].Clone); end; function TcxRegExprParserAlts.GetStartConnections: TcxRegExprStates; var I: Integer; begin Result := TcxRegExprStates.Create; for I := 0 to Count - 1 do Result.Add(Alt[I].GetStartConnections); end; function TcxRegExprParserAlts.Print: string; var I: Integer; begin Result := ''; for I := 0 to Count - 1 do Result := Result + Alt[I].Print; end; procedure TcxRegExprParserAlts.SetFinishConnections( AFinishState: TcxRegExprState); var I: Integer; begin for I := 0 to Count - 1 do Alt[I].SetFinishConnection(AFinishState); end; function TcxRegExprParserAlts.StartStateIsFinal: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if Alt[I].CanMissing then begin Result := True; Exit; end; Result := False; end; function TcxRegExprParserAlts.ThereIsEmptyAlt: Boolean; var I: Integer; begin for I := 0 to Count - 1 do if Alt[I].CanMissing then begin Result := True; Exit; end; Result := False; end; function TcxRegExprParserAlts.GetAlt(AIndex: Integer): TcxRegExprParserAlt; begin Result := TcxRegExprParserAlt(FAlts[AIndex]); end; function TcxRegExprParserAlts.GetCount: Integer; begin Result := FAlts.Count; end; function TcxRegExprParserAlts.GetLastAlt: TcxRegExprParserAlt; begin Result := TcxRegExprParserAlt(FAlts.Last); end; { TcxRegExpr } constructor TcxRegExpr.Create; begin inherited Create; FStream := TMemoryStream.Create; FErrors := TcxRegExprErrors.Create; FLexems := TcxLexems.Create; FBlocks := TList.Create; FAutomat := nil; FIndex := 0; FLexemIndex := 0; FLine := 1; FChar := 0; FFirstExpr := True; FCompiled := False; FUpdateOn := False; FCaseInsensitive := False; end; destructor TcxRegExpr.Destroy; begin Clear; FStream.Free; FLexems.Free; FBlocks.Free; FErrors.Free; if FAutomat <> nil then FAutomat.Free; inherited Destroy; end; procedure TcxRegExpr.Compile(AStream: TStream); begin if FFirstExpr then FFirstExpr := False else Clear; try FStream.LoadFromStream(AStream); except FErrors.Add(TcxRegExprError.Create(0, 0, cxGetResourceString(@scxRegExprNotAssignedSourceStream))); raise EcxRegExprError.Create(FErrors); end; if EmptyStream then begin FErrors.Add(TcxRegExprError.Create(0, 0, cxGetResourceString(@scxRegExprEmptySourceStream))); raise EcxRegExprError.Create(FErrors); end; ScanExpr; if FErrors.Count > 0 then raise EcxRegExprError.Create(FErrors); ParseExpr; if FErrors.Count > 0 then raise EcxRegExprError.Create(FErrors); FCompiled := True; if UpdateOn then FAutomat.Update; end; function TcxRegExpr.IsCompiled: Boolean; begin Result := FCompiled; end; function TcxRegExpr.IsFinal: Boolean; begin TestCompiledStatus; Result := FAutomat.IsFinal; end; function TcxRegExpr.IsStart: Boolean; begin TestCompiledStatus; Result := FAutomat.IsStart; end; function TcxRegExpr.Next(var AToken: Char): Boolean; begin TestCompiledStatus; Result := FAutomat.Next(AToken, FCaseInsensitive); if not FAutomat.IsFinal and Result and UpdateOn then FAutomat.Update; end; function TcxRegExpr.NextEx(const AString: string): string; var C: Char; I: Integer; begin TestCompiledStatus; Result := ''; for I := 1 to Length(AString) do begin C := AString[I]; if FAutomat.Next(C, FCaseInsensitive) then Result := Result + AString[I]; end; end; function TcxRegExpr.Prev: Boolean; begin TestCompiledStatus; if UpdateOn then FAutomat.ReUpdate; Result := FAutomat.Prev; end; function TcxRegExpr.Print: string; begin Result := FAutomat.Print; end; procedure TcxRegExpr.Reset; begin TestCompiledStatus; FAutomat.Reset; end; procedure TcxRegExpr.Clear; begin FStream.Size := 0; FErrors.Clear; FLexems.Clear; FBlocks.Clear; if FAutomat <> nil then FAutomat.Free; FAutomat := nil; FIndex := 0; FLexemIndex := 0; FChar := 0; FLine := 1; FCompiled := False; end; function TcxRegExpr.Decimal(AToken: Char): Boolean; begin if AToken in ['0','1','2','3','4','5','6','7','8','9'] then Result := True else Result := False; end; function TcxRegExpr.EmptyStream: Boolean; var AToken: Char; I: Integer; begin if FStream.Size = 0 then Result := True else begin I := 0; while LookToken(AToken, I) do begin if not Space(AToken) then begin Result := False; Exit; end; Inc(I); end; Result := True; end; end; function TcxRegExpr.CreateLexem(ALine: Integer; AChar: Integer; ACode: Integer; AValue: string): TcxLexem; begin Result.Line := ALine; Result.Char := AChar; Result.Code := ACode; Result.Value := AValue; end; function TcxRegExpr.GetLexem(var ALexem: TcxLexem): Boolean; begin if (FLexemIndex >= 0) and (FLexemIndex < FLexems.Count) then begin ALexem := FLexems[FLexemIndex]; Inc(FLexemIndex); Result := True; end else Result := False; end; function TcxRegExpr.GetToken(out AToken: Char): Boolean; begin Result := LookToken(AToken, 0); if Result then begin Inc(FIndex); if AToken = #13 then Inc(FLine); if AToken = #10 then FChar := 0 else Inc(FChar); end; end; function TcxRegExpr.GetStream: TStream; begin if FCompiled then Result := FStream else Result := nil; end; function TcxRegExpr.Hexadecimal(AToken: Char): Boolean; begin Result := (AToken >= '0') and (AToken <= '9') or (AToken >= 'A') and (AToken <= 'F') or (AToken >= 'a') and (AToken <= 'f'); end; function TcxRegExpr.LookToken(out AToken: Char; APtr: Integer): Boolean; begin Result := ((FIndex + APtr) < FStream.Size) and ((FIndex + APtr) >= 0); if Result then AToken := Char(PByteArray(FStream.Memory)[FIndex + APtr]); end; function TcxRegExpr.ParseAlt(AAlt: TcxRegExprParserAlt; Global: Boolean): Boolean; var ALexem: TcxLexem; ACurrentItem: TcxRegExprParserItem; procedure AddItem(AItem: TcxRegExprParserItem); begin ACurrentItem := AItem; AAlt.Add(AItem); end; procedure SetQuantifier(AQuantifier: TcxRegExprQuantifier); var ABlock: TcxRegExprParserBlockItem; begin if ACurrentItem.NotQuantifier then ACurrentItem.SetQuantifier(AQuantifier) else begin ABlock := TcxRegExprParserBlockItem.Create(AQuantifier); ABlock.Alts.AddAlt; ABlock.Alts.LastAlt.Add(ACurrentItem); ACurrentItem := ABlock; AAlt.FItems[AAlt.FItems.Count - 1] := ABlock; end; end; function CreateParameterQuantifierBlock(AIndex, ACount: Integer): TcxRegExprParserItem; begin if AIndex < (ACount - 1) then begin Result := TcxRegExprParserBlockItem.Create(TcxRegExprQuestionQuantifier.Create); with TcxRegExprParserBlockItem(Result).Alts do begin AddAlt; LastAlt.Add(ACurrentItem.Clone); LastAlt.Add(CreateParameterQuantifierBlock(AIndex + 1, ACount)); end; end else begin Result := ACurrentItem.Clone; Result.SetQuantifier(TcxRegExprQuestionQuantifier.Create); end; end; procedure SetParameterQuantifier(A, B: Integer); var ABlock: TcxRegExprParserBlockItem; AItem: TcxRegExprParserItem; I: Integer; begin if ACurrentItem.CanMissing then begin FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantUseParameterQuantifier))); Exit; end; ABlock := TcxRegExprParserBlockItem.Create(TcxRegExprSimpleQuantifier.Create); ABlock.Alts.AddAlt; for I := 0 to A - 1 do ABlock.Alts.LastAlt.Add(ACurrentItem.Clone); if B = -1 then begin AItem := ACurrentItem.Clone; AItem.SetQuantifier(TcxRegExprStarQuantifier.Create); ABlock.Alts.LastAlt.Add(AItem); end else if B > A then ABlock.Alts.LastAlt.Add(CreateParameterQuantifierBlock(A, B)); ACurrentItem := ABlock; AAlt.LastItem := ABlock; end; procedure SetQuestionQuantifier; begin SetQuantifier(TcxRegExprQuestionQuantifier.Create); end; procedure SetPlusQuantifier; begin if ACurrentItem.CanEmpty then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantUsePlusQuantifier))) else SetQuantifier(TcxRegExprPlusQuantifier.Create); end; procedure SetStarQuantifier; begin if ACurrentItem.CanEmpty then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantUseStarQuantifier))) else SetQuantifier(TcxRegExprStarQuantifier.Create); end; var RefNumber: Integer; A, B: Integer; begin ACurrentItem := nil; if GetLexem(ALexem) then begin if (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = '|') then begin FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantCreateEmptyAlt))); Result := True; Exit; end; if not Global then begin if (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = ')') then begin FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantCreateEmptyBlock))); Result := False; Exit; end; end; end else begin FErrors.Add(TcxRegExprError.Create(0, 0, cxGetResourceString(@scxRegExprCantCreateEmptyAlt))); Result := False; Exit; end; repeat case TcxRegExprLexemCode(ALexem.Code) of relcSymbol: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprSymbol.Create( ALexem.Value[1])))); relcSpecial: begin case ALexem.Value[1] of '|': begin Result := True; Exit; end; '(': AddItem(ParseBlock); ')': begin if Global then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalSymbol), [')']))) else begin Result := False; Exit; end; end; '[': AddItem(ParseEnumeration); ']': FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalSymbol), [']']))); '{': begin if ACurrentItem = nil then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprIncorrectParameterQuantifier))) else begin ParseQuantifier(A, B); SetParameterQuantifier(A, B); end; end; '}': FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalSymbol), ['}']))); '-': FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalSymbol), ['-']))); '?': begin if ACurrentItem = nil then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalQuantifier), ['?']))) else SetQuestionQuantifier; end; '+': begin if ACurrentItem = nil then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalQuantifier), ['+']))) else SetPlusQuantifier; end; '*': begin if ACurrentItem = nil then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalQuantifier), ['*']))) else SetStarQuantifier; end; end; end; relcInteger: FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprIllegalIntegerValue))); relcTimeSeparator: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprTimeSeparator.Create))); relcDateSeparator: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprDateSeparator.Create))); relcAll: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprAll.Create))); relcId: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprIdLetter.Create))); relcNotId: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprIdLetter.Create(True)))); relcDigit: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprDigit.Create))); relcNotDigit: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprDigit.Create(True)))); relcSpace: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprSpace.Create))); relcNotSpace: AddItem( TcxRegExprParserSimpleItem.Create( TcxRegExprSimpleState.Create( TcxRegExprSpace.Create(True)))); relcReference: begin RefNumber := StrToInt(ALexem.Value) - 1; if RefNumber >= FBlocks.Count then FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprTooBigReferenceNumber))) else AddItem(TcxRegExprParserItem(FBlocks[RefNumber]).Clone); end; end; until not GetLexem(ALexem); Result := False; end; function TcxRegExpr.ParseBlock: TcxRegExprParserBlockItem; begin Result := TcxRegExprParserBlockItem.Create; FBlocks.Add(Result); repeat Result.Alts.AddAlt; until not ParseAlt(Result.Alts.LastAlt, False); end; function TcxRegExpr.ParseEnumeration: TcxRegExprParserSimpleItem; var ALexem: TcxLexem; ALexem1: TcxLexem; Enumeration: TcxRegExprUserEnumeration; begin GetLexem(ALexem); if (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = '^') then begin Enumeration := TcxRegExprUserEnumeration.Create(True); GetLexem(ALexem); end else Enumeration := TcxRegExprUserEnumeration.Create; Result := TcxRegExprParserSimpleItem.Create(TcxRegExprSimpleState.Create(Enumeration)); if (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = ']') then begin FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprCantCreateEmptyEnum))); Exit; end; repeat GetLexem(ALexem1); if (TcxRegExprLexemCode(ALexem1.Code) = relcSpecial) and (ALexem1.Value[1] = '-') then begin GetLexem(ALexem1); if ALexem.Value[1] < ALexem1.Value[1] then Enumeration.Add(TcxRegExprSubrange.Create(ALexem.Value[1], ALexem1.Value[1])) else FErrors.Add(TcxRegExprError.Create(ALexem1.Line, ALexem1.Char, cxGetResourceString(@scxRegExprSubrangeOrder))); GetLexem(ALexem); while (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = '-') do begin FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, Format(cxGetResourceString(@scxRegExprIllegalSymbol), ['-']))); GetLexem(ALexem); end; end else begin case TcxRegExprLexemCode(ALexem.Code) of relcTimeSeparator: Enumeration.Add(TcxRegExprTimeSeparator.Create); relcDateSeparator: Enumeration.Add(TcxRegExprDateSeparator.Create); relcAll: Enumeration.Add(TcxRegExprAll.Create); relcId: Enumeration.Add(TcxRegExprIdLetter.Create); relcNotId: Enumeration.Add(TcxRegExprIdLetter.Create(True)); relcDigit: Enumeration.Add(TcxRegExprDigit.Create); relcNotDigit: Enumeration.Add(TcxRegExprDigit.Create(True)); relcSpace: Enumeration.Add(TcxRegExprSpace.Create); relcNotSpace: Enumeration.Add(TcxRegExprSpace.Create(True)); else Enumeration.Add(TcxRegExprSymbol.Create(ALexem.Value[1])); end; ALexem := ALexem1; end; until (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value[1] = ']'); end; procedure TcxRegExpr.ParseExpr; var Expr: TcxRegExprParserAlts; begin Expr := TcxRegExprParserAlts.Create; repeat Expr.AddAlt; until not ParseAlt(Expr.LastAlt); if FErrors.Count > 0 then Expr.Free else begin Expr.CreateConnections; Expr.CreateFinalStates; FAutomat := TcxRegExprAutomat.Create(Expr, Self); end; end; procedure TcxRegExpr.ParseQuantifier(var A: Integer; var B: Integer); var ALexem: TcxLexem; begin GetLexem(ALexem); if TcxRegExprLexemCode(ALexem.Code) = relcInteger then begin A := StrToInt(ALexem.Value); GetLexem(ALexem); if TcxRegExprLexemCode(ALexem.Code) = relcSpecial then begin if ALexem.Value = ',' then begin GetLexem(ALexem); if TcxRegExprLexemCode(ALexem.Code) = relcInteger then begin B := StrToInt(ALexem.Value); if B >= A then begin GetLexem(ALexem); if (TcxRegExprLexemCode(ALexem.Code) = relcSpecial) and (ALexem.Value = '}') then Exit; end; end else if TcxRegExprLexemCode(ALexem.Code) = relcSpecial then begin if ALexem.Value = '}' then begin B := -1; Exit; end; end; end else if ALexem.Value = '}' then begin B := A; Exit; end; end; end; FErrors.Add(TcxRegExprError.Create(ALexem.Line, ALexem.Char, cxGetResourceString(@scxRegExprIncorrectParameterQuantifier))); end; procedure TcxRegExpr.ScanASCII(ALine: Integer; AChar: Integer); var AToken: Char; ALexem: TcxLexem; begin if GetToken(AToken) then begin if Hexadecimal(AToken)then ALexem.Value := AToken else begin FErrors.Add(TcxRegExprError.Create(FLine, FChar, Format(cxGetResourceString(@scxRegExprHexNumberExpected), [AToken]))); Exit; end; if GetToken(AToken) then begin if Hexadecimal(AToken)then ALexem.Value := ALexem.Value + AToken else begin FErrors.Add(TcxRegExprError.Create(FLine, FChar, Format(cxGetResourceString(@scxRegExprHexNumberExpected), [AToken]))); Exit; end; ALexem.Line := ALine; ALexem.Char := AChar; ALexem.Code := Ord(relcSymbol); ALexem.Value := Char(StrToInt('$' + ALexem.Value)); FLexems.Add(ALexem); end else FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, cxGetResourceString(@scxRegExprHexNumberExpected0))); end else FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, cxGetResourceString(@scxRegExprHexNumberExpected0))); end; procedure TcxRegExpr.ScanClass; var AToken: Char; Flag: Boolean; _Line: Integer; _Char: Integer; begin while GetToken(AToken) do begin if Space(AToken) then Continue; case AToken of '''': begin ScanString; Break; end; '^': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); Break; end; ':': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcTimeSeparator), AToken)); Break; end; '/': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcDateSeparator), AToken)); Break; end; '\': begin ScanEscape(FLine, FChar); Break; end; ']': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); Exit; end; else begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSymbol), AToken)); Break; end; end; end; while GetToken(AToken) do begin if Space(AToken) then Continue; case AToken of '''': ScanString; ']': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); Exit; end; '-': begin Flag := False; _Line := FLine; _Char := FChar; while LookToken(AToken, 0) do begin if Space(AToken) then begin GetToken(AToken); Continue; end else begin if AToken = ']' then FLexems.Add(CreateLexem(_Line, _Char, Ord(relcSymbol), '-')) else FLexems.Add(CreateLexem(_Line, _Char, Ord(relcSpecial), '-')); Flag := True; Break; end; end; if not Flag then begin FLexems.Add(CreateLexem(_Line, _Char, Ord(relcSpecial), '-')); FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, Format(cxGetResourceString(@scxRegExprMissing), [']']))); Exit; end; end; ':': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcTimeSeparator), AToken)); '/': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcDateSeparator), AToken)); '\': ScanEscape(FLine, FChar); else FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSymbol), AToken)); end; end; FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, Format(cxGetResourceString(@scxRegExprMissing), [']']))); end; procedure TcxRegExpr.ScanExpr; var AToken: Char; AOpenSkobCounter: Integer; begin AOpenSkobCounter := 0; while GetToken(AToken) do begin if Space(AToken) then Continue; case AToken of '''': ScanString; '[': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); ScanClass; end; '{': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); ScanQuantifier; end; '.': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcAll), AToken)); ':': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcTimeSeparator), AToken)); '/': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcDateSeparator), AToken)); '\': ScanEscape(FLine, FChar); '(': begin Inc(AOpenSkobCounter); FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); end; ')': begin Dec(AOpenSkobCounter); FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); end; '+', '*', '?', '|': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); else FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSymbol), AToken)); end; end; if AOpenSkobCounter > 0 then FErrors.Add(TcxRegExprError.Create(0, 0, Format(cxGetResourceString(@scxRegExprMissing), [')']))) else if AOpenSkobCounter < 0 then FErrors.Add(TcxRegExprError.Create(0, 0, Format(cxGetResourceString(@scxRegExprUnnecessary), [')']))); end; procedure TcxRegExpr.ScanEscape(ALine: Integer; AChar: Integer); var AToken: Char; begin while GetToken(AToken) do begin if Decimal(AToken) and (AToken <> '0') then begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcReference), AToken)); Exit; end else begin if Space(AToken) then begin FErrors.Add(TcxRegExprError.Create(FLine, FChar, cxGetResourceString(@scxRegExprIncorrectSpace))); Exit; end; case AToken of 'x': begin ScanASCII(ALine, AChar); Exit; end; 'w': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcId), AToken)); Exit; end; 'W': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcNotId), AToken)); Exit; end; 'd': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcDigit), AToken)); Exit; end; 'D': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcNotDigit), AToken)); Exit; end; 's': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSpace), AToken)); Exit; end; 'S': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcNotSpace), AToken)); Exit; end; 't': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #9)); Exit; end; 'n': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #10)); Exit; end; 'r': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #13)); Exit; end; 'f': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #12)); Exit; end; 'a': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #7)); Exit; end; 'e': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), #27)); Exit; end; 'p': begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), DecimalSeparator)); Exit; end else begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcSymbol), AToken)); Exit; end; end; end; end; end; function TcxRegExpr.ScanInteger(ALine, AChar: Integer; var AToken: Char): Boolean; var AValue: string; begin AValue := AToken; while GetToken(AToken) do begin if Decimal(AToken) then AValue := AValue + AToken else begin FLexems.Add(CreateLexem(ALine, AChar, Ord(relcInteger), AValue)); Result := True; Exit; end; end; FLexems.Add(CreateLexem(ALine, AChar, Ord(relcInteger), AValue)); Result := False; end; procedure TcxRegExpr.ScanQuantifier; var AToken: Char; ALexem: TcxLexem; begin ALexem.Value := ''; while GetToken(AToken) do begin if Space(AToken) then Continue else if Decimal(AToken) then begin if not ScanInteger(FLine, FChar, AToken) then Break; if Space(AToken) then Continue; end; case AToken of '''': FErrors.Add(TcxRegExprError.Create(FLine, FChar, Format(cxGetResourceString(@scxRegExprIllegalSymbol), [' '' ']))); ',': FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); '}': begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSpecial), AToken)); Exit; end; else FErrors.Add(TcxRegExprError.Create(FLine, FChar, Format(cxGetResourceString(@scxRegExprIllegalSymbol), [AToken]))); end; end; FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, Format(cxGetResourceString(@scxRegExprMissing), ['}']))); end; procedure TcxRegExpr.ScanString; var AToken: Char; begin while GetToken(AToken) do begin if AToken = '''' then begin if LookToken(AToken, 0) then begin if AToken = '''' then begin FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSymbol), '''')); GetToken(AToken); Continue; end else Exit; end else Exit; end else FLexems.Add(CreateLexem(FLine, FChar, Ord(relcSymbol), AToken)); end; FErrors.Add(TcxRegExprError.Create(FLine, FChar + 1, Format(cxGetResourceString(@scxRegExprMissing), [' '' ']))); end; procedure TcxRegExpr.SetUpdateOn(AUpdateOn: Boolean); begin FUpdateOn := AUpdateOn; if FCompiled then if FUpdateOn then FAutomat.Update; end; function TcxRegExpr.Space(AToken: Char): Boolean; begin Result := IsSpaceChar(AToken); end; procedure TcxRegExpr.SymbolDelete; begin if Assigned(FOnSymbolDelete) then FOnSymbolDelete; end; procedure TcxRegExpr.SymbolUpdate(ASymbol: Char); begin if Assigned(FOnSymbolUpdate) then FOnSymbolUpdate(ASymbol); end; procedure TcxRegExpr.TestCompiledStatus; begin if not FCompiled then raise EcxEditError.Create(cxGetResourceString(@scxRegExprNotCompiled)); end; function IsTextFullValid(const AText, AMask: string): Boolean; var ARegExpr: TcxRegExpr; AStream: TStringStream; C: Char; I: Integer; begin ARegExpr := TcxRegExpr.Create; AStream := TStringStream.Create(AMask); Result := False; try try ARegExpr.Compile(AStream); Result := True; for I := 1 to Length(AText) do begin C := AText[I]; if not ARegExpr.Next(C) then begin Result := False; Break; end; end; if Result then if not ARegExpr.IsFinal then Result := False; except on E: EcxRegExprError do raise EcxRegExprError.Create(E.Errors.Clone); end; finally AStream.Free; ARegExpr.Free; end; end; function IsTextValid(const AText, AMask: string): Boolean; var ARegExpr: TcxRegExpr; AStream: TStringStream; C: Char; I: Integer; begin ARegExpr := TcxRegExpr.Create; AStream := TStringStream.Create(AMask); Result := False; try try ARegExpr.Compile(AStream); Result := True; for I := 1 to Length(AText) do begin C := AText[I]; if not ARegExpr.Next(C) then begin Result := False; Break; end; end; except on E: EcxRegExprError do raise EcxRegExprError.Create(E.Errors.Clone); end; finally AStream.Free; ARegExpr.Free; end; end; end.