RegExpr.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:145k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit RegExpr;
  2. {
  3.      TRegExpr class library
  4.      Delphi Regular Expressions
  5.  Copyright (c) 1999-2004 Andrey V. Sorokin, St.Petersburg, Russia
  6.  You may use this software in any kind of development,
  7.  including comercial, redistribute, and modify it freely,
  8.  under the following restrictions :
  9.  1. This software is provided as it is, without any kind of
  10.     warranty given. Use it at Your own risk.The author is not
  11.     responsible for any consequences of use of this software.
  12.  2. The origin of this software may not be mispresented, You
  13.     must not claim that You wrote the original software. If
  14.     You use this software in any kind of product, it would be
  15.     appreciated that there in a information box, or in the
  16.     documentation would be an acknowledgement like
  17.      Partial Copyright (c) 2004 Andrey V. Sorokin
  18.                                 http://RegExpStudio.com
  19.                                 mailto:anso@mail.ru
  20.  3. You may not have any income from distributing this source
  21.     (or altered version of it) to other developers. When You
  22.     use this product in a comercial package, the source may
  23.     not be charged seperatly.
  24.  4. Altered versions must be plainly marked as such, and must
  25.     not be misrepresented as being the original software.
  26.  5. RegExp Studio application and all the visual components as 
  27.     well as documentation is not part of the TRegExpr library 
  28.     and is not free for usage.
  29.                                     mailto:anso@mail.ru
  30.                                     http://RegExpStudio.com
  31.                                     http://anso.da.ru/
  32. }
  33. interface
  34. // ======== Determine compiler
  35. {$IFDEF VER80} Sorry, TRegExpr is for 32-bits Delphi only. Delphi 1 is not supported (and whos really care today?!). {$ENDIF}
  36. {$IFDEF VER90} {$DEFINE D2} {$ENDIF} // D2
  37. {$IFDEF VER93} {$DEFINE D2} {$ENDIF} // CPPB 1
  38. {$IFDEF VER100} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // D3
  39. {$IFDEF VER110} {$DEFINE D4} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // CPPB 3
  40. {$IFDEF VER120} {$DEFINE D4} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // D4
  41. {$IFDEF VER130} {$DEFINE D5} {$DEFINE D4} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // D5
  42. {$IFDEF VER140} {$DEFINE D6} {$DEFINE D5} {$DEFINE D4} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // D6
  43. {$IFDEF VER150} {$DEFINE D7} {$DEFINE D6} {$DEFINE D5} {$DEFINE D4} {$DEFINE D3} {$DEFINE D2} {$ENDIF} // D7
  44. // ======== Define base compiler options
  45. {$BOOLEVAL OFF}
  46. {$EXTENDEDSYNTAX ON}
  47. {$LONGSTRINGS ON}
  48. {$OPTIMIZATION ON}
  49. {$IFDEF D6}
  50.   {$WARN SYMBOL_PLATFORM OFF} // Suppress .Net warnings
  51. {$ENDIF}
  52. {$IFDEF D7}
  53.   {$WARN UNSAFE_CAST OFF} // Suppress .Net warnings
  54.   {$WARN UNSAFE_TYPE OFF} // Suppress .Net warnings
  55.   {$WARN UNSAFE_CODE OFF} // Suppress .Net warnings
  56. {$ENDIF}
  57. {$IFDEF FPC}
  58.  {$MODE DELPHI} // Delphi-compatible mode in FreePascal
  59. {$ENDIF}
  60. // ======== Define options for TRegExpr engine
  61. {.$DEFINE UniCode} // Unicode support
  62. {$DEFINE RegExpPCodeDump} // p-code dumping (see Dump method)
  63. {$IFNDEF FPC} // the option is not supported in FreePascal
  64.  {$DEFINE reRealExceptionAddr} // exceptions will point to appropriate source line, not to Error procedure
  65. {$ENDIF}
  66. {$DEFINE ComplexBraces} // support braces in complex cases
  67. {$IFNDEF UniCode} // the option applicable only for non-UniCode mode
  68.  {$DEFINE UseSetOfChar} // Significant optimization by using set of char
  69. {$ENDIF}
  70. {$IFDEF UseSetOfChar}
  71.  {$DEFINE UseFirstCharSet} // Fast skip between matches for r.e. that starts with determined set of chars
  72. {$ENDIF}
  73. // ======== Define Pascal-language options
  74. // Define 'UseAsserts' option (do not edit this definitions).
  75. // Asserts used to catch 'strange bugs' in TRegExpr implementation (when something goes
  76. // completely wrong). You can swith asserts on/off with help of {$C+}/{$C-} compiler options.
  77. {$IFDEF D3} {$DEFINE UseAsserts} {$ENDIF}
  78. {$IFDEF FPC} {$DEFINE UseAsserts} {$ENDIF}
  79. // Define 'use subroutine parameters default values' option (do not edit this definition).
  80. {$IFDEF D4} {$DEFINE DefParam} {$ENDIF}
  81. // Define 'OverMeth' options, to use method overloading (do not edit this definitions).
  82. {$IFDEF D5} {$DEFINE OverMeth} {$ENDIF}
  83. {$IFDEF FPC} {$DEFINE OverMeth} {$ENDIF}
  84. uses
  85.  Classes,  // TStrings in Split method
  86.  SysUtils; // Exception
  87. type
  88.  {$IFDEF UniCode}
  89.  PRegExprChar = PWideChar;
  90.  RegExprString = WideString;
  91.  REChar = WideChar;
  92.  {$ELSE}
  93.  PRegExprChar = PChar;
  94.  RegExprString = AnsiString; //###0.952 was string
  95.  REChar = Char;
  96.  {$ENDIF}
  97.  TREOp = REChar; // internal p-code type //###0.933
  98.  PREOp = ^TREOp;
  99.  TRENextOff = integer; // internal Next "pointer" (offset to current p-code) //###0.933
  100.  PRENextOff = ^TRENextOff; // used for extracting Next "pointers" from compiled r.e. //###0.933
  101.  TREBracesArg = integer; // type of {m,n} arguments
  102.  PREBracesArg = ^TREBracesArg;
  103. const
  104.  REOpSz = SizeOf (TREOp) div SizeOf (REChar); // size of p-code in RegExprString units
  105.  RENextOffSz = SizeOf (TRENextOff) div SizeOf (REChar); // size of Next 'pointer' -"-
  106.  REBracesArgSz = SizeOf (TREBracesArg) div SizeOf (REChar); // size of BRACES arguments -"-
  107. type
  108.  TRegExprInvertCaseFunction = function (const Ch : REChar) : REChar
  109.                                of object;
  110. const
  111.   EscChar = ''; // 'Escape'-char ('' in common r.e.) used for escaping metachars (w, d etc).
  112.   RegExprModifierI : boolean = False;    // default value for ModifierI
  113.   RegExprModifierR : boolean = True;     // default value for ModifierR
  114.   RegExprModifierS : boolean = True;     // default value for ModifierS
  115.   RegExprModifierG : boolean = True;     // default value for ModifierG
  116.   RegExprModifierM : boolean = False;    // default value for ModifierM
  117.   RegExprModifierX : boolean = False;    // default value for ModifierX
  118.   RegExprSpaceChars : RegExprString =    // default value for SpaceChars
  119.   ' '#$9#$A#$D#$C;
  120.   RegExprWordChars : RegExprString =     // default value for WordChars
  121.     '0123456789' //###0.940
  122.   + 'abcdefghijklmnopqrstuvwxyz'
  123.   + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_';
  124.   RegExprLineSeparators : RegExprString =// default value for LineSeparators
  125.    #$d#$a{$IFDEF UniCode}+#$b#$c#$2028#$2029#$85{$ENDIF}; //###0.947
  126.   RegExprLinePairedSeparator : RegExprString =// default value for LinePairedSeparator
  127.    #$d#$a;
  128.   { if You need Unix-styled line separators (only n), then use:
  129.   RegExprLineSeparators = #$a;
  130.   RegExprLinePairedSeparator = '';
  131.   }
  132. const
  133.  NSUBEXP = 15; // max number of subexpression //###0.929
  134.  // Cannot be more than NSUBEXPMAX
  135.  // Be carefull - don't use values which overflow CLOSE opcode
  136.  // (in this case you'll get compiler erorr).
  137.  // Big NSUBEXP will cause more slow work and more stack required
  138.  NSUBEXPMAX = 255; // Max possible value for NSUBEXP. //###0.945
  139.  // Don't change it! It's defined by internal TRegExpr design.
  140.  MaxBracesArg = $7FFFFFFF - 1; // max value for {n,m} arguments //###0.933
  141.  {$IFDEF ComplexBraces}
  142.  LoopStackMax = 10; // max depth of loops stack //###0.925
  143.  {$ENDIF}
  144.  TinySetLen = 3;
  145.  // if range includes more then TinySetLen chars, //###0.934
  146.  // then use full (32 bytes) ANYOFFULL instead of ANYOF[BUT]TINYSET
  147.  // !!! Attension ! If you change TinySetLen, you must
  148.  // change code marked as "//!!!TinySet"
  149. type
  150. {$IFDEF UseSetOfChar}
  151.  PSetOfREChar = ^TSetOfREChar;
  152.  TSetOfREChar = set of REChar;
  153. {$ENDIF}
  154.  TRegExpr = class;
  155.  TRegExprReplaceFunction = function (ARegExpr : TRegExpr): string
  156.                                of object;
  157.  TRegExpr = class
  158.    private
  159.     startp : array [0 .. NSUBEXP - 1] of PRegExprChar; // founded expr starting points
  160.     endp : array [0 .. NSUBEXP - 1] of PRegExprChar; // founded expr end points
  161.     {$IFDEF ComplexBraces}
  162.     LoopStack : array [1 .. LoopStackMax] of integer; // state before entering loop
  163.     LoopStackIdx : integer; // 0 - out of all loops
  164.     {$ENDIF}
  165.     // The "internal use only" fields to pass info from compile
  166.     // to execute that permits the execute phase to run lots faster on
  167.     // simple cases.
  168.     regstart : REChar; // char that must begin a match; '' if none obvious
  169.     reganch : REChar; // is the match anchored (at beginning-of-line only)?
  170.     regmust : PRegExprChar; // string (pointer into program) that match must include, or nil
  171.     regmlen : integer; // length of regmust string
  172.     // Regstart and reganch permit very fast decisions on suitable starting points
  173.     // for a match, cutting down the work a lot.  Regmust permits fast rejection
  174.     // of lines that cannot possibly match.  The regmust tests are costly enough
  175.     // that regcomp() supplies a regmust only if the r.e. contains something
  176.     // potentially expensive (at present, the only such thing detected is * or +
  177.     // at the start of the r.e., which can involve a lot of backup).  Regmlen is
  178.     // supplied because the test in regexec() needs it and regcomp() is computing
  179.     // it anyway.
  180.     {$IFDEF UseFirstCharSet} //###0.929
  181.     FirstCharSet : TSetOfREChar;
  182.     {$ENDIF}
  183.     // work variables for Exec's routins - save stack in recursion}
  184.     reginput : PRegExprChar; // String-input pointer.
  185.     fInputStart : PRegExprChar; // Pointer to first char of input string.
  186.     fInputEnd : PRegExprChar; // Pointer to char AFTER last char of input string
  187.     // work variables for compiler's routines
  188.     regparse : PRegExprChar;  // Input-scan pointer.
  189.     regnpar : integer; // count.
  190.     regdummy : char;
  191.     regcode : PRegExprChar;   // Code-emit pointer; @regdummy = don't.
  192.     regsize : integer; // Code size.
  193.     regexpbeg : PRegExprChar; // only for error handling. Contains
  194.     // pointer to beginning of r.e. while compiling
  195.     fExprIsCompiled : boolean; // true if r.e. successfully compiled
  196.     // programm is essentially a linear encoding
  197.     // of a nondeterministic finite-state machine (aka syntax charts or
  198.     // "railroad normal form" in parsing technology).  Each node is an opcode
  199.     // plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  200.     // all nodes except BRANCH implement concatenation; a "next" pointer with
  201.     // a BRANCH on both ends of it is connecting two alternatives.  (Here we
  202.     // have one of the subtle syntax dependencies:  an individual BRANCH (as
  203.     // opposed to a collection of them) is never concatenated with anything
  204.     // because of operator precedence.)  The operand of some types of node is
  205.     // a literal string; for others, it is a node leading into a sub-FSM.  In
  206.     // particular, the operand of a BRANCH node is the first node of the branch.
  207.     // (NB this is *not* a tree structure:  the tail of the branch connects
  208.     // to the thing following the set of BRANCHes.)  The opcodes are:
  209.     programm : PRegExprChar; // Unwarranted chumminess with compiler.
  210.     fExpression : PRegExprChar; // source of compiled r.e.
  211.     fInputString : PRegExprChar; // input string
  212.     fLastError : integer; // see Error, LastError
  213.     fModifiers : integer; // modifiers
  214.     fCompModifiers : integer; // compiler's copy of modifiers
  215.     fProgModifiers : integer; // modifiers values from last programm compilation
  216.     fSpaceChars : RegExprString; //###0.927
  217.     fWordChars : RegExprString; //###0.929
  218.     fInvertCase : TRegExprInvertCaseFunction; //###0.927
  219.     fLineSeparators : RegExprString; //###0.941
  220.     fLinePairedSeparatorAssigned : boolean;
  221.     fLinePairedSeparatorHead,
  222.     fLinePairedSeparatorTail : REChar;
  223.     {$IFNDEF UniCode}
  224.     fLineSeparatorsSet : set of REChar;
  225.     {$ENDIF}
  226.     procedure InvalidateProgramm;
  227.     // Mark programm as have to be [re]compiled
  228.     function IsProgrammOk : boolean; //###0.941
  229.     // Check if we can use precompiled r.e. or
  230.     // [re]compile it if something changed
  231.     function GetExpression : RegExprString;
  232.     procedure SetExpression (const s : RegExprString);
  233.     function GetModifierStr : RegExprString;
  234.     class function ParseModifiersStr (const AModifiers : RegExprString;
  235.       var AModifiersInt : integer) : boolean; //###0.941 class function now
  236.     // Parse AModifiers string and return true and set AModifiersInt
  237.     // if it's in format 'ismxrg-ismxrg'.
  238.     procedure SetModifierStr (const AModifiers : RegExprString);
  239.     function GetModifier (AIndex : integer) : boolean;
  240.     procedure SetModifier (AIndex : integer; ASet : boolean);
  241.     procedure Error (AErrorID : integer); virtual; // error handler.
  242.     // Default handler raise exception ERegExpr with
  243.     // Message = ErrorMsg (AErrorID), ErrorCode = AErrorID
  244.     // and CompilerErrorPos = value of property CompilerErrorPos.
  245.     {==================== Compiler section ===================}
  246.     function CompileRegExpr (exp : PRegExprChar) : boolean;
  247.     // compile a regular expression into internal code
  248.     procedure Tail (p : PRegExprChar; val : PRegExprChar);
  249.     // set the next-pointer at the end of a node chain
  250.     procedure OpTail (p : PRegExprChar; val : PRegExprChar);
  251.     // regoptail - regtail on operand of first argument; nop if operandless
  252.     function EmitNode (op : TREOp) : PRegExprChar;
  253.     // regnode - emit a node, return location
  254.     procedure EmitC (b : REChar);
  255.     // emit (if appropriate) a byte of code
  256.     procedure InsertOperator (op : TREOp; opnd : PRegExprChar; sz : integer); //###0.90
  257.     // insert an operator in front of already-emitted operand
  258.     // Means relocating the operand.
  259.     function ParseReg (paren : integer; var flagp : integer) : PRegExprChar;
  260.     // regular expression, i.e. main body or parenthesized thing
  261.     function ParseBranch (var flagp : integer) : PRegExprChar;
  262.     // one alternative of an | operator
  263.     function ParsePiece (var flagp : integer) : PRegExprChar;
  264.     // something followed by possible [*+?]
  265.     function ParseAtom (var flagp : integer) : PRegExprChar;
  266.     // the lowest level
  267.     function GetCompilerErrorPos : integer;
  268.     // current pos in r.e. - for error hanling
  269.     {$IFDEF UseFirstCharSet} //###0.929
  270.     procedure FillFirstCharSet (prog : PRegExprChar);
  271.     {$ENDIF}
  272.     {===================== Mathing section ===================}
  273.     function regrepeat (p : PRegExprChar; AMax : integer) : integer;
  274.     // repeatedly match something simple, report how many
  275.     function regnext (p : PRegExprChar) : PRegExprChar;
  276.     // dig the "next" pointer out of a node
  277.     function MatchPrim (prog : PRegExprChar) : boolean;
  278.     // recursively matching routine
  279.     function ExecPrim (AOffset: integer) : boolean;
  280.     // Exec for stored InputString
  281.     {$IFDEF RegExpPCodeDump}
  282.     function DumpOp (op : REChar) : RegExprString;
  283.     {$ENDIF}
  284.     function GetSubExprMatchCount : integer;
  285.     function GetMatchPos (Idx : integer) : integer;
  286.     function GetMatchLen (Idx : integer) : integer;
  287.     function GetMatch (Idx : integer) : RegExprString;
  288.     function GetInputString : RegExprString;
  289.     procedure SetInputString (const AInputString : RegExprString);
  290.     {$IFNDEF UseSetOfChar}
  291.     function StrScanCI (s : PRegExprChar; ch : REChar) : PRegExprChar; //###0.928
  292.     {$ENDIF}
  293.     procedure SetLineSeparators (const AStr : RegExprString);
  294.     procedure SetLinePairedSeparator (const AStr : RegExprString);
  295.     function GetLinePairedSeparator : RegExprString;
  296.    public
  297.     constructor Create;
  298.     destructor Destroy; override;
  299.     class function VersionMajor : integer; //###0.944
  300.     class function VersionMinor : integer; //###0.944
  301.     property Expression : RegExprString read GetExpression write SetExpression;
  302.     // Regular expression.
  303.     // For optimization, TRegExpr will automatically compiles it into 'P-code'
  304.     // (You can see it with help of Dump method) and stores in internal
  305.     // structures. Real [re]compilation occures only when it really needed -
  306.     // while calling Exec[Next], Substitute, Dump, etc
  307.     // and only if Expression or other P-code affected properties was changed
  308.     // after last [re]compilation.
  309.     // If any errors while [re]compilation occures, Error method is called
  310.     // (by default Error raises exception - see below)
  311.     property ModifierStr : RegExprString read GetModifierStr write SetModifierStr;
  312.     // Set/get default values of r.e.syntax modifiers. Modifiers in
  313.     // r.e. (?ismx-ismx) will replace this default values.
  314.     // If you try to set unsupported modifier, Error will be called
  315.     // (by defaul Error raises exception ERegExpr).
  316.     property ModifierI : boolean index 1 read GetModifier write SetModifier;
  317.     // Modifier /i - caseinsensitive, initialized from RegExprModifierI
  318.     property ModifierR : boolean index 2 read GetModifier write SetModifier;
  319.     // Modifier /r - use r.e.syntax extended for russian,
  320.     // (was property ExtSyntaxEnabled in previous versions)
  321.     // If true, then