system.regularexpressions.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2023 The Free Pascal team
  4. Delphi-compatible Record based Regular expressions API unit.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit System.RegularExpressions;
  12. {$mode objfpc}
  13. {$modeswitch advancedrecords}
  14. interface
  15. uses
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. System.SysUtils, System.RegularExpressionsCore;
  18. {$ELSE}
  19. SysUtils, System.RegularExpressionsCore;
  20. {$ENDIF}
  21. const
  22. MatchGrowDelta = 32;
  23. type
  24. TRegExOption = (roNone, roIgnoreCase, roMultiLine, roExplicitCapture,
  25. roCompiled, roSingleLine, roIgnorePatternSpace, roNotEmpty);
  26. TRegExOptions = set of TRegExOption;
  27. TREStringDynArray = Array of TREString;
  28. IObjectReference = Interface ['{69E6C6D3-764F-4A6F-BC3D-5F4E32A2E4F4}']
  29. Function GetObject : TObject;
  30. end;
  31. { TObjectReference }
  32. TObjectReference = Class(TInterfacedObject,IObjectReference)
  33. Private
  34. FObject : TObject;
  35. Protected
  36. Function GetObject : TObject;
  37. Public
  38. Constructor Create(aObject : TObject);
  39. Destructor Destroy; override;
  40. Property Obj : TObject Read GetObject;
  41. end;
  42. { TGroup }
  43. TGroup = record
  44. private
  45. FIndex: Integer;
  46. FLength: Integer;
  47. FName: TREString;
  48. FSuccess: Boolean;
  49. FValue: TREString;
  50. public
  51. constructor Create(const aValue,aName: TREString; aIndex, aLength: Integer; aSuccess: Boolean);
  52. property Index: Integer read FIndex;
  53. property Length: Integer read FLength;
  54. property Success: Boolean read FSuccess;
  55. property Value: TREString read FValue;
  56. property Name: TREString read FName;
  57. end;
  58. TGroupArray = Array of TGroup;
  59. TGroupCollectionEnumerator = class;
  60. { TGroupCollection }
  61. TGroupCollection = record
  62. private
  63. FGroups : TGroupArray;
  64. function GetCount: Integer;
  65. function GetItem(const aIndex: Variant): TGroup;
  66. function IndexOfName(const aName : TREString): Integer;
  67. public
  68. constructor Create(const aGroups : TGroupArray);
  69. function GetEnumerator: TGroupCollectionEnumerator;
  70. property Count: Integer read GetCount;
  71. property Item[const Index: Variant]: TGroup read GetItem; default;
  72. end;
  73. { TGroupCollectionEnumerator }
  74. TGroupCollectionEnumerator = class
  75. private
  76. FGroups: TGroupCollection;
  77. FCurrent: Integer;
  78. public
  79. constructor Create(const aGroups: TGroupCollection);
  80. function GetCurrent: TGroup;
  81. function MoveNext: Boolean;
  82. property Current: TGroup read GetCurrent;
  83. end;
  84. { TMatch }
  85. PMatch = ^TMatch;
  86. TMatch = record
  87. private
  88. FGroup: TGroup;
  89. FGroups: TGroupCollection;
  90. FRegex : IObjectReference;
  91. FNext: PMatch;
  92. function GetIndex: Integer;
  93. function GetLength: Integer;
  94. function GetSuccess: Boolean;
  95. function GetValue: TREString;
  96. procedure SetNext(const aNext: PMatch);
  97. public
  98. constructor Create(const aRegex: IObjectReference; const aValue: TREString; aIndex, aLength: Integer; aSuccess: Boolean);
  99. function NextMatch: TMatch;
  100. function Result_(const Pattern: TREString): TREString;
  101. property Groups: TGroupCollection read FGroups;
  102. property Index: Integer read GetIndex;
  103. property Length: Integer read GetLength;
  104. property Success: Boolean read GetSuccess;
  105. property Value: TREString read GetValue;
  106. end;
  107. TMatchArray = array of TMatch;
  108. TMatchCollectionEnumerator = class;
  109. { TMatchCollection }
  110. TMatchCollection = record
  111. private
  112. FMatches: TMatchArray;
  113. function GetCount: Integer;
  114. function GetItem(Index: Integer): TMatch;
  115. public
  116. constructor Create(const aRegex : IObjectReference; const aInput: TREString; aOptions: TRegExOptions; aStartPos: Integer);
  117. function GetEnumerator: TMatchCollectionEnumerator;
  118. property Count: Integer read GetCount;
  119. property Item[Index: Integer]: TMatch read GetItem; default;
  120. end;
  121. { TMatchCollectionEnumerator }
  122. TMatchCollectionEnumerator = class
  123. private
  124. FCollection: TMatchCollection;
  125. FCurrent: Integer;
  126. public
  127. constructor Create(const aCollection: TMatchCollection);
  128. function GetCurrent: TMatch;
  129. function MoveNext: Boolean;
  130. property Current: TMatch read GetCurrent;
  131. end;
  132. TMatchEvaluator = function(const Match: TMatch): TREString of object;
  133. { TRegEx }
  134. TRegEx = record
  135. private
  136. FOptions: TRegExOptions;
  137. FRef: IObjectReference;
  138. FRegEx: TPerlRegEx;
  139. public
  140. constructor Create(const aPattern: TREString; aOptions: TRegExOptions = [roNotEmpty]);
  141. function IsMatch(const aInput: TREString): Boolean; overload;
  142. function IsMatch(const aInput: TREString; aStartPos: Integer): Boolean; overload;
  143. class function IsMatch(const aInput, aPattern: TREString): Boolean;overload; static;
  144. class function IsMatch(const aInput, aPattern: TREString; aOptions: TRegExOptions): Boolean; overload; static;
  145. class function Escape(const aString: TREString; aUseWildCards: Boolean = False): TREString; static;
  146. function Match(const aInput: TREString): TMatch; overload;
  147. function Match(const aInput: TREString; aStartPos: Integer): TMatch; overload;
  148. function Match(const aInput: TREString; aStartPos, aLength: Integer): TMatch; overload;
  149. class function Match(const aInput, aPattern: TREString): TMatch; overload; static;
  150. class function Match(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatch; overload; static;
  151. function Matches(const aInput: TREString): TMatchCollection; overload;
  152. function Matches(const aInput: TREString; aStartPos: Integer): TMatchCollection; overload;
  153. class function Matches(const aInput, aPattern: TREString): TMatchCollection; overload; static;
  154. class function Matches(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatchCollection; overload; static;
  155. function Replace(const aInput, aReplacement: TREString): TREString; overload;
  156. function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator): TREString; overload;
  157. function Replace(const aInput, aReplacement: TREString; aCount: Integer): TREString; overload;
  158. function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator; aCount: Integer): TREString; overload;
  159. class function Replace(const aInput, aPattern, aReplacement: TREString): TREString; overload; static;
  160. class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator): TREString; overload; static;
  161. class function Replace(const aInput, aPattern, aReplacement: TREString; aOptions: TRegExOptions): TREString; overload; static;
  162. class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator; aOptions: TRegExOptions): TREString; overload; static;
  163. function Split(const aInput: TREString): TREStringDynArray; overload; inline;
  164. function Split(const aInput: TREString; aCount: Integer): TREStringDynArray; overload; inline;
  165. function Split(const aInput: TREString; aCount, aStartPos: Integer): TREStringDynArray; overload;
  166. class function Split(const aInput, aPattern: TREString): TREStringDynArray; overload; static;
  167. class function Split(const aInput, aPattern: TREString; aOptions: TRegExOptions): TREStringDynArray; overload; static;
  168. end;
  169. { TRegExHelper }
  170. TRegExHelper = record helper for TRegEx
  171. public
  172. procedure Study(Options: TRegExStudyOptions = []);
  173. procedure AddRawOptions(const Value: Integer);
  174. end;
  175. function RegExOptionsToPCREOptions(Value: TRegExOptions): TPerlRegExOptions;
  176. implementation
  177. uses
  178. {$IFDEF FPC_DOTTEDUNITS}
  179. System.Classes, System.Variants, System.RegularExpressionsConsts;
  180. {$ELSE}
  181. Classes, Variants, System.RegularExpressionsConsts;
  182. {$ENDIF}
  183. Type
  184. { TMatcher }
  185. TMatcher = Class(TObject)
  186. FMatchEvaluator: TMatchEvaluator;
  187. FRef: IObjectReference;
  188. Constructor Create(AMatchEvaluator: TMatchEvaluator; aRef: IObjectReference);
  189. procedure ReplaceEvent(Sender: TObject; var ReplaceWith: TREString);
  190. end;
  191. Function GetRegEx(aRef : IObjectReference) : TPerlRegEx; inline;
  192. begin
  193. Result:=aRef.GetObject as TPerlRegex;
  194. end;
  195. function RegExOptionsToPCREOptions(Value: TRegExOptions): TPerlRegExOptions;
  196. Procedure Add(aFlag : TRegExOption; aOpt : TPerlRegExOption);
  197. begin
  198. if aFlag in Value then
  199. Include(Result,aOpt);
  200. end;
  201. begin
  202. Result := [];
  203. Add(roIgnoreCase,preCaseLess);
  204. Add(roMultiLine,preMultiLine);
  205. Add(roExplicitCapture,preNoAutoCapture);
  206. Add(roSingleLine,preSingleLine);
  207. Add(roIgnorePatternSpace,preExtended);
  208. end;
  209. { TMatcher }
  210. constructor TMatcher.Create(AMatchEvaluator: TMatchEvaluator; aRef: IObjectReference);
  211. begin
  212. FMatchEvaluator:=AMatchEvaluator;
  213. FRef:=aRef;
  214. end;
  215. procedure TMatcher.ReplaceEvent(Sender: TObject; var ReplaceWith: TREString);
  216. var
  217. M: TMatch;
  218. RE : TPerlRegEx;
  219. begin
  220. if Assigned(FMatchEvaluator) then
  221. begin
  222. RE:=Sender as TPerlRegEx;
  223. M:=TMatch.Create(FRef,RE.MatchedText,RE.MatchedOffset,Re.MatchedLength,True);
  224. ReplaceWith:=FMatchEvaluator(M);
  225. end;
  226. end;
  227. { TObjectReference }
  228. function TObjectReference.GetObject: TObject;
  229. begin
  230. Result:=FObject;
  231. end;
  232. constructor TObjectReference.Create(aObject: TObject);
  233. begin
  234. FObject:=aObject;
  235. end;
  236. destructor TObjectReference.Destroy;
  237. begin
  238. FreeAndNil(FObject);
  239. inherited Destroy;
  240. end;
  241. { TGroup }
  242. constructor TGroup.Create(const aValue, aName: TREString; aIndex, aLength: Integer; aSuccess: Boolean);
  243. begin
  244. FValue:=aValue;
  245. FIndex:=aIndex;
  246. FLength:=aLength;
  247. FSuccess:=aSuccess;
  248. FName:=aName;
  249. end;
  250. { TGroupCollectionEnumerator }
  251. constructor TGroupCollectionEnumerator.Create(const aGroups: TGroupCollection);
  252. begin
  253. FGroups:=aGroups;
  254. FCurrent:=-1;
  255. end;
  256. function TGroupCollectionEnumerator.GetCurrent: TGroup;
  257. begin
  258. Result:=FGroups.FGroups[FCurrent];
  259. end;
  260. function TGroupCollectionEnumerator.MoveNext: Boolean;
  261. begin
  262. Result:=FCurrent<Length(FGroups.FGroups)-1;
  263. if Result then
  264. Inc(FCurrent);
  265. end;
  266. { TMatch }
  267. function TMatch.GetIndex: Integer;
  268. begin
  269. Result:=FGroup.Index;
  270. end;
  271. function TMatch.GetLength: Integer;
  272. begin
  273. Result:=FGroup.Length;
  274. end;
  275. function TMatch.GetSuccess: Boolean;
  276. begin
  277. Result:=FGroup.Success;
  278. end;
  279. function TMatch.GetValue: TREString;
  280. begin
  281. Result:=FGRoup.Value;
  282. end;
  283. procedure TMatch.SetNext(const aNext: PMatch);
  284. begin
  285. FRegex:=Nil;
  286. FNext:=aNext;
  287. end;
  288. constructor TMatch.Create(const aRegex: IObjectReference; const aValue: TREString; aIndex, aLength: Integer; aSuccess: Boolean);
  289. var
  290. N : TREStringDynArray;
  291. G : TGroupArray;
  292. RE : TPerlRegEx;
  293. i,idx : Integer;
  294. GN : TREString;
  295. begin
  296. G:=Default(TGroupArray);
  297. N:=Default(TREStringDynArray);
  298. FRegex:=aRegex;
  299. FGroup:=TGroup.Create(aValue,'',aIndex,aLength,aSuccess);
  300. if Success then
  301. begin
  302. RE:=GetRegEx(FRegEx);
  303. SetLength(N,RE.GroupCount+1);
  304. For I:=0 to RE.NameCount-1 do
  305. begin
  306. GN:=RE.Names[i];
  307. Idx:=RE.NamedGroup(GN);
  308. if Idx<>-1 then
  309. N[Idx]:=GN;
  310. end;
  311. SetLength(G,RE.GroupCount+1);
  312. For I:=0 to RE.GroupCount do
  313. G[i]:=TGroup.Create(RE.Groups[I],N[i],RE.GroupOffsets[i],RE.GroupLengths[I],aSuccess);
  314. end;
  315. FGroups:=TGroupCollection.Create(G);
  316. end;
  317. function TMatch.NextMatch: TMatch;
  318. var
  319. RE : TPerlRegEx;
  320. begin
  321. if Assigned(FRegex) then
  322. begin
  323. RE:=GetRegEx(FRegex);
  324. if RE.MatchAgain then
  325. Result:=TMatch.Create(FRegex,RE.MatchedText,RE.MatchedOffset,RE.MatchedLength,True)
  326. else
  327. Result:=TMatch.Create(FRegex,'',0,0,False);
  328. end
  329. else if Assigned(FNext) then
  330. Result:=FNext^
  331. else
  332. Result:=TMatch.Create(FRegex,'',0,0,False);
  333. end;
  334. function TMatch.Result_(const Pattern: TREString): TREString;
  335. var
  336. RE: TPerlRegEx;
  337. begin
  338. RE:=GetRegEx(FRegex);
  339. RE.Replacement:=Pattern;
  340. Result:=RE.ComputeReplacement;
  341. end;
  342. { TMatchCollection }
  343. constructor TMatchCollection.Create(const aRegex: IObjectReference; const aInput: TREString; aOptions: TRegExOptions;
  344. aStartPos: Integer);
  345. var
  346. Found: Boolean;
  347. Len : Integer;
  348. RE: TPerlRegEx;
  349. begin
  350. RE:=GetRegEx(aRegex);
  351. RE.Subject:=aInput;
  352. RE.Options:=RegExOptionsToPCREOptions(AOptions);
  353. RE.Start:=aStartPos;
  354. Len:=0;
  355. SetLength(FMatches,0);
  356. Found:=RE.Match;
  357. while Found do
  358. begin
  359. if Len>=Length(FMatches) then
  360. SetLength(FMatches,Length(FMatches)+MatchGrowDelta);
  361. FMatches[Len]:=TMatch.Create(aRegex,RE.MatchedText,RE.MatchedOffset,RE.MatchedLength,Found);
  362. if Len>0 then
  363. FMatches[Len-1].SetNext(@FMatches[Len]);
  364. Found:=RE.MatchAgain;
  365. Inc(Len);
  366. end;
  367. FMatches[Len-1].SetNext(Nil);
  368. if Len<Length(FMatches) then
  369. SetLength(FMatches,Len);
  370. end;
  371. function TMatchCollection.GetCount: Integer;
  372. begin
  373. Result:=Length(FMatches);
  374. end;
  375. function TMatchCollection.GetItem(Index: Integer): TMatch;
  376. begin
  377. Result:=FMatches[Index];
  378. end;
  379. function TMatchCollection.GetEnumerator: TMatchCollectionEnumerator;
  380. begin
  381. Result:=TMatchCollectionEnumerator.Create(Self);
  382. end;
  383. { TMatchCollectionEnumerator }
  384. constructor TMatchCollectionEnumerator.Create(const aCollection: TMatchCollection);
  385. begin
  386. FCollection:=aCollection;
  387. FCurrent:=-1;
  388. end;
  389. function TMatchCollectionEnumerator.GetCurrent: TMatch;
  390. begin
  391. Result:=FCollection.FMatches[FCurrent];
  392. end;
  393. function TMatchCollectionEnumerator.MoveNext: Boolean;
  394. begin
  395. Result:=FCurrent<Length(FCollection.FMatches)-1;
  396. If Result then
  397. Inc(FCurrent);
  398. end;
  399. { TRegEx }
  400. constructor TRegEx.Create(const aPattern: TREString; aOptions: TRegExOptions);
  401. begin
  402. FRegEx:=TPerlRegEx.Create;
  403. Foptions:=aOPtions;
  404. FRegex.Options:=RegExOptionsToPCREOptions(aOptions);
  405. FRegex.RegEx:=aPattern;
  406. FRef:=TObjectReference.Create(FRegex);
  407. end;
  408. function TRegEx.IsMatch(const aInput: TREString): Boolean;
  409. begin
  410. Result:=IsMatch(aInput,1);
  411. end;
  412. function TRegEx.IsMatch(const aInput: TREString; aStartPos: Integer): Boolean;
  413. begin
  414. FRegex.Subject:=aInput;
  415. FRegex.Start:=aStartPos;
  416. Result:=FRegex.Match;
  417. end;
  418. class function TRegEx.IsMatch(const aInput, aPattern: TREString): Boolean;
  419. begin
  420. Result:=IsMatch(aInput,aPattern,[roNotEmpty]);
  421. end;
  422. class function TRegEx.IsMatch(const aInput, aPattern: TREString; aOptions: TRegExOptions): Boolean;
  423. var
  424. RE : TRegEx;
  425. begin
  426. RE:=TRegex.Create(aPattern,aOptions);
  427. Result:=RE.IsMatch(aInput);
  428. end;
  429. class function TRegEx.Escape(const aString: TREString; aUseWildCards: Boolean): TREString;
  430. function esc(const s : TREString; c : char; rep : string) : string;
  431. begin
  432. Result:=StringReplace(s,'\'+c,rep,[rfReplaceAll]);
  433. Result:=StringReplace(Result,Rep+rep,'\'+c,[rfReplaceAll]);
  434. end;
  435. begin
  436. Result:=TPerlRegEx.EscapeRegExChars(aString);
  437. Result:=StringReplace(Result,#13#10,'\r\n',[rfReplaceAll]);
  438. if Not aUseWildCards then
  439. exit;
  440. Result:=Esc(Result,'?','(.)');
  441. Result:=Esc(Result,'*','(.*)');
  442. end;
  443. function TRegEx.Match(const aInput: TREString): TMatch;
  444. begin
  445. Result:=Match(aInput,1,Length(aInput));
  446. end;
  447. function TRegEx.Match(const aInput: TREString; aStartPos: Integer): TMatch;
  448. begin
  449. Result:=Match(aInput,aStartPos,Length(aInput));
  450. end;
  451. function TRegEx.Match(const aInput: TREString; aStartPos, aLength: Integer): TMatch;
  452. var
  453. Found: Boolean;
  454. L,O : Integer;
  455. S : TREString;
  456. begin
  457. L:=0;
  458. O:=0;
  459. S:='';
  460. With FRegEx do
  461. begin
  462. Subject:=aInput;
  463. FRegex.Start:=aStartPos;
  464. FRegex.Stop:=aStartPos+aLength-1;
  465. Found:=Match;
  466. if Found then
  467. begin
  468. S:=MatchedText;
  469. O:=MatchedOffset;
  470. L:=MatchedLength;
  471. end;
  472. end;
  473. Result:=TMatch.Create(FRef,S,O,L,Found);
  474. end;
  475. class function TRegEx.Match(const aInput, aPattern: TREString): TMatch;
  476. var
  477. RE : TRegEx;
  478. begin
  479. RE:=TRegex.Create(aPattern);
  480. Result:=RE.Match(aInput);
  481. end;
  482. class function TRegEx.Match(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatch;
  483. var
  484. RE : TRegEx;
  485. begin
  486. RE:=TRegex.Create(aPattern,aOptions);
  487. Result:=RE.Match(aInput);
  488. end;
  489. function TRegEx.Matches(const aInput: TREString): TMatchCollection;
  490. begin
  491. Result:=TMatchCollection.Create(FRef,aInput,FOptions,1);
  492. end;
  493. function TRegEx.Matches(const aInput: TREString; aStartPos: Integer): TMatchCollection;
  494. begin
  495. Result:=TMatchCollection.Create(FRef,aInput,FOptions,aStartPos);
  496. end;
  497. class function TRegEx.Matches(const aInput, aPattern: TREString): TMatchCollection;
  498. var
  499. RE: TRegEx;
  500. begin
  501. RE:=TRegEx.Create(aPattern);
  502. Result:=RE.Matches(aInput);
  503. end;
  504. class function TRegEx.Matches(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatchCollection;
  505. var
  506. RE: TRegEx;
  507. begin
  508. RE:=TRegEx.Create(aPattern,aOptions);
  509. Result:=RE.Matches(aInput);
  510. end;
  511. function TRegEx.Replace(const aInput, aReplacement: TREString): TREString;
  512. begin
  513. FRegEx.Subject:=aInput;
  514. FRegEx.Replacement:=aReplacement;
  515. FRegEx.ReplaceAll;
  516. Result:=FRegEx.Subject;
  517. end;
  518. function TRegEx.Replace(const aInput: TREString; aEvaluator: TMatchEvaluator): TREString;
  519. var
  520. M : TMatcher;
  521. begin
  522. FRegEx.Subject:=aInput;
  523. M:=TMatcher.Create(aEvaluator,FRef);
  524. try
  525. FRegEx.OnReplace:[email protected];
  526. FRegEx.ReplaceAll;
  527. Result := FRegEx.Subject;
  528. finally
  529. M.Free;
  530. end;
  531. end;
  532. function TRegEx.Replace(const aInput, aReplacement: TREString; aCount: Integer): TREString;
  533. var
  534. I: Integer;
  535. begin
  536. if aCount<0 then
  537. Exit(Replace(aInput,aReplacement));
  538. I:=0;
  539. FRegEx.Subject:=aInput;
  540. FRegEx.Replacement:=aReplacement;
  541. if FRegEx.Match then
  542. repeat
  543. Inc(I);
  544. FRegEx.Replace;
  545. until (not FRegEx.MatchAgain) or (I>=aCount);
  546. Result:=FRegEx.Subject;
  547. end;
  548. function TRegEx.Replace(const aInput: TREString; aEvaluator: TMatchEvaluator; aCount: Integer): TREString;
  549. var
  550. M : TMatcher;
  551. I : integer;
  552. begin
  553. FRegEx.Subject:=aInput;
  554. M:=TMatcher.Create(aEvaluator,FRef);
  555. try
  556. I:=0;
  557. FRegEx.Subject:=aInput;
  558. FRegEx.OnReplace:[email protected];
  559. if FRegEx.Match then
  560. repeat
  561. Inc(I);
  562. FRegEx.Replace;
  563. until (not FRegEx.MatchAgain) or (I>=aCount);
  564. Result:=FRegEx.Subject;
  565. finally
  566. M.Free;
  567. end;
  568. end;
  569. class function TRegEx.Replace(const aInput, aPattern, aReplacement: TREString): TREString;
  570. var
  571. RE : TRegex;
  572. begin
  573. RE:=TRegex.Create(aPattern);
  574. Result:=RE.Replace(aInput,aReplacement);
  575. end;
  576. class function TRegEx.Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator): TREString;
  577. begin
  578. Result:=Replace(aInput,aPattern,aEvaluator,[roNotEmpty]);
  579. end;
  580. class function TRegEx.Replace(const aInput, aPattern, aReplacement: TREString; aOptions: TRegExOptions): TREString;
  581. var
  582. RE : TRegex;
  583. begin
  584. RE:=TRegex.Create(aPattern,aOptions);
  585. Result:=RE.Replace(aInput,aReplacement);
  586. end;
  587. class function TRegEx.Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator; aOptions: TRegExOptions): TREString;
  588. var
  589. RE: TRegEx;
  590. begin
  591. RE:=TRegEx.Create(aPattern,aOptions);
  592. Result:=RE.Replace(aInput,aEvaluator);
  593. end;
  594. function TRegEx.Split(const aInput: TREString): TREStringDynArray;
  595. begin
  596. Result:=Split(aInput,0,1);
  597. end;
  598. function TRegEx.Split(const aInput: TREString; aCount: Integer): TREStringDynArray;
  599. begin
  600. Result:=Split(aInput,aCount,1);
  601. end;
  602. function TRegEx.Split(const aInput: TREString; aCount, aStartPos: Integer): TREStringDynArray;
  603. var
  604. L: TStrings;
  605. begin
  606. Result:=Default(TREStringDynArray);
  607. if aInput='' then
  608. exit;
  609. FRegEx.Subject:=aInput;
  610. Result:=FRegEx.SplitCapture(aCount,aStartPos);
  611. end;
  612. class function TRegEx.Split(const aInput, aPattern: TREString): TREStringDynArray;
  613. var
  614. RE: TRegEx;
  615. begin
  616. RE:=TRegEx.Create(aPattern);
  617. Result:= RE.Split(aInput);
  618. end;
  619. class function TRegEx.Split(const aInput, aPattern: TREString; aOptions: TRegExOptions): TREStringDynArray;
  620. var
  621. RE: TRegEx;
  622. begin
  623. RE:=TRegEx.Create(aPattern,aOptions);
  624. Result:=RE.Split(aInput);
  625. end;
  626. { TRegExHelper }
  627. procedure TRegExHelper.Study(Options: TRegExStudyOptions);
  628. begin
  629. end;
  630. procedure TRegExHelper.AddRawOptions(const Value: Integer);
  631. begin
  632. end;
  633. function TGroupCollection.GetCount: Integer;
  634. begin
  635. Result:=Length(FGroups);
  636. end;
  637. function TGroupCollection.GetItem(const aIndex: Variant): TGroup;
  638. var
  639. Idx: Integer;
  640. IdxIsName : Boolean;
  641. begin
  642. IdxIsName:=False;
  643. Idx:=-1;
  644. case VarType(aIndex) of
  645. varByte,
  646. varWord,
  647. varLongWord,
  648. varQWord,
  649. varSmallint,
  650. varShortInt,
  651. varInteger,
  652. varInt64:
  653. Idx:=aIndex;
  654. varString,
  655. varUString,
  656. varOleStr:
  657. begin
  658. Idx:=IndexOfName(TREString(aIndex));
  659. idxIsName:=True;
  660. end
  661. else
  662. raise ERegularExpressionError.Create(SRegExInvalidIndexType);
  663. end;
  664. if (Idx>=0) and (Idx<Length(FGroups)) then
  665. Result:=FGroups[Idx]
  666. else if (Idx=-1) and (IdxIsName) then
  667. raise ERegularExpressionError.CreateFmt(SRegExInvalidGroupName,[TREString(aIndex)])
  668. else
  669. raise ERegularExpressionError.CreateFmt(SRegExIndexOutOfBounds,[Idx]);
  670. end;
  671. function TGroupCollection.IndexOfName(const aName: TREString): Integer;
  672. begin
  673. Result:=Length(FGroups)-1;
  674. While (Result>=0) and (FGroups[Result].Name<>'') and Not SameText(aName,FGroups[Result].Name) do
  675. Dec(Result);
  676. end;
  677. constructor TGroupCollection.Create(const aGroups: TGroupArray);
  678. begin
  679. FGroups:=aGroups;
  680. end;
  681. function TGroupCollection.GetEnumerator: TGroupCollectionEnumerator;
  682. begin
  683. Result:=TGroupCollectionEnumerator.Create(Self);
  684. end;
  685. end.