utcregexapi.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. unit utcregexapi;
  2. {$mode objfpc}{$H+}
  3. { $DEFINE USEWIDESTRING}
  4. interface
  5. uses
  6. Classes, SysUtils, fpcunit, testutils, testregistry, system.regularexpressionscore, system.regularexpressions;
  7. type
  8. { TTestRegExpCore }
  9. TTestRegExp = class(TTestCase)
  10. private
  11. FRegex: TRegEx;
  12. function DoReplacer(const Match: TMatch): TREString;
  13. Protected
  14. Property Regex : TRegEx Read FRegex Write FRegex;
  15. Public
  16. Procedure SetUp; override;
  17. Procedure TearDown; override;
  18. Published
  19. Procedure TestIsMatch;
  20. Procedure TestIsMatchStartPos;
  21. Procedure TestClassIsMatch;
  22. Procedure TestClassIsMatchOptions;
  23. Procedure TestEscape;
  24. Procedure TestMatch;
  25. Procedure TestMatchNoMatch;
  26. Procedure TestMatchStartPos;
  27. Procedure TestMatchStartPosLength;
  28. Procedure TestClassMatch;
  29. Procedure TestClassMatchOptions;
  30. Procedure TestMatches;
  31. Procedure TestMatchesStartPos;
  32. Procedure TestClassMatches;
  33. Procedure TestClassMatchesOptions;
  34. Procedure TestReplace;
  35. Procedure TestReplaceEval;
  36. Procedure TestReplaceCount;
  37. Procedure TestReplaceEvalCount;
  38. Procedure TestClassReplace;
  39. Procedure TestClassReplaceEval;
  40. Procedure TestClassReplaceOptions;
  41. Procedure TestClassReplaceEvalOptions;
  42. {
  43. function Split(const aInput: TREString): TREStringDynArray; overload; inline;
  44. function Split(const aInput: TREString; aCount: Integer): TREStringDynArray; overload; inline;
  45. function Split(const aInput: TREString; aCount, aStartPos: Integer): TREStringDynArray; overload;
  46. class function Split(const aInput, aPattern: TREString): TREStringDynArray; overload; static;
  47. class function Split(const aInput, aPattern: TREString; aOptions: TRegExOptions): TREStringDynArray; overload; static;
  48. }
  49. end;
  50. implementation
  51. Const
  52. TestStr = 'xyz abba abbba abbbba zyx';
  53. TestExpr = 'a(b*)a';
  54. { TTestRegExpr}
  55. procedure TTestRegExp.SetUp;
  56. begin
  57. inherited SetUp;
  58. FRegex:=Default(TRegex);
  59. end;
  60. procedure TTestRegExp.TearDown;
  61. begin
  62. FRegex:=Default(TRegex);
  63. inherited TearDown;
  64. end;
  65. procedure TTestRegExp.TestIsMatch;
  66. begin
  67. // function IsMatch(const aInput: TREString): Boolean; overload;
  68. Regex:=TRegex.Create(TestExpr);
  69. AssertTrue('Correct match',Regex.IsMatch(TestStr));
  70. end;
  71. procedure TTestRegExp.TestIsMatchStartPos;
  72. begin
  73. // function IsMatch(const aInput: TREString; aStartPos: Integer): Boolean; overload;
  74. Regex:=TRegex.Create(TestExpr);
  75. AssertTrue('Correct match',Regex.IsMatch(TestStr,Pos('abbba',TestStr)));
  76. AssertFalse('No match match at pos',Regex.IsMatch(TestStr,Pos('zyx',TestStr)));
  77. end;
  78. procedure TTestRegExp.TestClassIsMatch;
  79. begin
  80. // class function IsMatch(const aInput, aPattern: TREString): Boolean;overload; static;
  81. AssertTrue('Correct match',TRegex.IsMatch(TestStr,TestExpr));
  82. AssertFalse('No match',TRegex.IsMatch(TestStr,TestExpr+'xyz'));
  83. end;
  84. procedure TTestRegExp.TestClassIsMatchOptions;
  85. begin
  86. // class function IsMatch(const aInput, aPattern: TREString; aOptions: TRegExOptions): Boolean; overload; static;
  87. AssertTrue('Correct match',TRegex.IsMatch(UpperCase(TestStr),TestExpr,[roIgnoreCase]));
  88. AssertFalse('No match',TRegex.IsMatch(UpperCase(TestStr),TestExpr+'xyz',[roIgnoreCase]));
  89. end;
  90. procedure TTestRegExp.TestEscape;
  91. begin
  92. // class function Escape(const aString: TREString; aUseWildCards: Boolean = False): TREString; static;
  93. AssertEquals('Wildcard ?','(.)',TRegex.Escape('?',True));
  94. AssertEquals('Wildcard ?','\?',TRegex.Escape('??',True));
  95. AssertEquals('Wildcard *','(.*)',TRegex.Escape('*',True));
  96. AssertEquals('Wildcard ?','\*',TRegex.Escape('**',True));
  97. AssertEquals('CRLF','\r\n',TRegex.Escape(#13#10,True));
  98. end;
  99. Procedure DumpMatch(M : TMatch);
  100. var
  101. I : Integer;
  102. begin
  103. Writeln('Match value: ',M.Value);
  104. Writeln('Match index: ',M.Index);
  105. Writeln('Match length: ',M.Length);
  106. Writeln('Match group count: ',M.Groups.Count);
  107. for I:=0 to M.Groups.Count-1 do
  108. begin
  109. Writeln('Group ',I);
  110. Writeln(Format('Match group %d value: ',[i]),M.Groups[i].Value);
  111. Writeln(Format('Match group %d index: ',[i]),M.Groups[i].Index);
  112. Writeln(Format('Match group %d length: ',[i]),M.Groups[i].Length);
  113. end;
  114. end;
  115. procedure TTestRegExp.TestMatch;
  116. var
  117. M : TMatch;
  118. begin
  119. // function Match(const aInput: TREString): TMatch; overload;
  120. RegEx:=TRegex.Create(TestExpr);
  121. M:=RegEx.Match(TestStr);
  122. AssertTrue('Match 0 result: ',M.Success);
  123. AssertEquals('Match 0 value: ','abba',M.Value);
  124. AssertEquals('Match 0 index: ',5,M.Index);
  125. AssertEquals('Match 0 length: ',4,M.Length);
  126. AssertEquals('Match 0 group count: ',2,M.Groups.Count);
  127. AssertEquals('Match 0 group 0 value: ','abba',M.Groups[0].Value);
  128. AssertEquals('Match 0 group 0 index: ',5,M.Groups[0].Index);
  129. AssertEquals('Match 0 group 0 length: ',4,M.Groups[0].Length);
  130. AssertEquals('Match 0 group 1 value: ','bb',M.Groups[1].Value);
  131. AssertEquals('Match 0 group 1 index: ',6,M.Groups[1].Index);
  132. AssertEquals('Match 0 group 1 length: ',2,M.Groups[1].Length);
  133. M:=M.NextMatch;
  134. AssertTrue('Match 1 result: ',M.Success);
  135. AssertEquals('Match 1 value: ','abbba',M.Value);
  136. AssertEquals('Match 1 index: ',10,M.Index);
  137. AssertEquals('Match 1 length: ',5,M.Length);
  138. M:=M.NextMatch;
  139. AssertTrue('Match 2 result: ',M.Success);
  140. AssertEquals('Match 2 value: ','abbbba',M.Value);
  141. AssertEquals('Match 2 index: ',16,M.Index);
  142. AssertEquals('Match 2 length: ',6,M.Length);
  143. M:=M.NextMatch;
  144. AssertFalse('Match 3 value: ',M.Success);
  145. end;
  146. procedure TTestRegExp.TestMatchNoMatch;
  147. var
  148. M : TMatch;
  149. begin
  150. RegEx:=TRegex.Create(TestExpr+'xyz');
  151. M:=RegEx.Match(TestStr);
  152. AssertFalse('Success',M.Success);
  153. AssertEquals('No match value','',M.Value);
  154. AssertEquals('No match Index',0,M.Index);
  155. AssertEquals('No match legth',0,M.Length);
  156. end;
  157. procedure TTestRegExp.TestMatchStartPos;
  158. var
  159. M : TMatch;
  160. P : Integer;
  161. begin
  162. // function Match(const aInput: TREString): TMatch; overload;
  163. RegEx:=TRegex.Create(TestExpr);
  164. P:=Pos('abbba',TestStr);
  165. M:=RegEx.Match(TestStr,P);
  166. // DumpMatch(M);
  167. AssertTrue('Match value: ',M.Success);
  168. AssertEquals('Match value: ','abbba',M.Value);
  169. AssertEquals('Match index: ',10,M.Index);
  170. AssertEquals('Match length: ',5,M.Length);
  171. AssertEquals('Match group count: ',2,M.Groups.Count);
  172. AssertEquals('Match group 0 value: ','abbba',M.Groups[0].Value);
  173. AssertEquals('Match group 0 index: ',10,M.Groups[0].Index);
  174. AssertEquals('Match group 0 length: ',5,M.Groups[0].Length);
  175. AssertEquals('Match group 1 value: ','bbb',M.Groups[1].Value);
  176. AssertEquals('Match group 1 index: ',11,M.Groups[1].Index);
  177. AssertEquals('Match group 1 length: ',3,M.Groups[1].Length);
  178. M:=M.NextMatch;
  179. AssertTrue('Match value: ',M.Success);
  180. end;
  181. procedure TTestRegExp.TestMatchStartPosLength;
  182. var
  183. M : TMatch;
  184. P : Integer;
  185. begin
  186. // function Match(const aInput: TREString): TMatch; overload;
  187. RegEx:=TRegex.Create(TestExpr);
  188. P:=Pos('abbba',TestStr);
  189. M:=RegEx.Match(TestStr,P,5);
  190. // DumpMatch(M);
  191. AssertTrue('Match value: ',M.Success);
  192. AssertEquals('Match value: ','abbba',M.Value);
  193. AssertEquals('Match index: ',10,M.Index);
  194. AssertEquals('Match length: ',5,M.Length);
  195. M:=M.NextMatch;
  196. AssertFalse('No more matches: ',M.Success);
  197. end;
  198. procedure TTestRegExp.TestClassMatch;
  199. var
  200. M : TMatch;
  201. begin
  202. // class function Match(const aInput, aPattern: TREString): TMatch; overload; static;
  203. M:=TRegex.Match(TestStr,TestExpr);
  204. AssertTrue('Match result: ',M.Success);
  205. AssertEquals('Match value: ','abba',M.Value);
  206. end;
  207. procedure TTestRegExp.TestClassMatchOptions;
  208. // class function Match(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatch; overload; static;
  209. var
  210. M : TMatch;
  211. begin
  212. // class function Match(const aInput, aPattern: TREString): TMatch; overload; static;
  213. M:=TRegex.Match(UpperCase(TestStr),TestExpr,[roIgnoreCase]);
  214. AssertTrue('Match result: ',M.Success);
  215. AssertEquals('Match value: ','ABBA',M.Value);
  216. end;
  217. procedure TTestRegExp.TestMatches;
  218. var
  219. MS : TMatchCollection;
  220. M,M2 : TMatch;
  221. begin
  222. // function Matches(const aInput: TREString): TMatchCollection; overload;
  223. RegEx:=TRegex.Create(TestExpr);
  224. MS:=RegEx.Matches(TestStr);
  225. AssertEquals('Match count',3,MS.Count);
  226. M:=MS[0];
  227. AssertTrue('Match 0 result: ',M.Success);
  228. AssertEquals('Match 0 value: ','abba',M.Value);
  229. AssertEquals('Match 0 index: ',5,M.Index);
  230. AssertEquals('Match 0 length: ',4,M.Length);
  231. AssertEquals('Match 0 group count: ',2,M.Groups.Count);
  232. AssertEquals('Match 0 group 0 value: ','abba',M.Groups[0].Value);
  233. AssertEquals('Match 0 group 0 index: ',5,M.Groups[0].Index);
  234. AssertEquals('Match 0 group 0 length: ',4,M.Groups[0].Length);
  235. AssertEquals('Match 0 group 1 value: ','bb',M.Groups[1].Value);
  236. AssertEquals('Match 0 group 1 index: ',6,M.Groups[1].Index);
  237. AssertEquals('Match 0 group 1 length: ',2,M.Groups[1].Length);
  238. M2:=M.NextMatch;
  239. M:=MS[1];
  240. AssertTrue('Match 1 resul: ',M.Success);
  241. AssertEquals('Match 1 value: ','abbba',M.Value);
  242. AssertEquals('NextMatch value: ','abbba',M2.Value);
  243. AssertEquals('Match 1 index: ',10,M.Index);
  244. AssertEquals('Match 1 length: ',5,M.Length);
  245. M:=MS[2];
  246. AssertTrue('Match 2 result: ',M.Success);
  247. AssertEquals('Match 2 value: ','abbbba',M.Value);
  248. AssertEquals('Match 2 index: ',16,M.Index);
  249. AssertEquals('Match 2 length: ',6,M.Length);
  250. M:=M.NextMatch;
  251. AssertFalse('Match value: ',M.Success);
  252. end;
  253. procedure TTestRegExp.TestMatchesStartPos;
  254. var
  255. MS : TMatchCollection;
  256. M : TMatch;
  257. begin
  258. // function Matches(const aInput: TREString; aStartPos: Integer): TMatchCollection; overload;
  259. RegEx:=TRegex.Create(TestExpr);
  260. MS:=RegEx.Matches(TestStr,9);
  261. AssertEquals('Match count',2,MS.Count);
  262. M:=MS[0];
  263. AssertTrue('Match 1 resul: ',M.Success);
  264. AssertEquals('Match 1 value: ','abbba',M.Value);
  265. M:=MS[1];
  266. AssertTrue('Match 1 resul: ',M.Success);
  267. AssertEquals('Match 1 value: ','abbbba',M.Value);
  268. end;
  269. procedure TTestRegExp.TestClassMatches;
  270. var
  271. MS : TMatchCollection;
  272. M : TMatch;
  273. begin
  274. // class function Matches(const aInput, aPattern: TREString): TMatchCollection; overload; static;
  275. MS:=TRegEx.Matches(TestStr,TestExpr);
  276. AssertEquals('Match count',3,MS.Count);
  277. M:=MS[0];
  278. AssertTrue('Match 0 result: ',M.Success);
  279. AssertEquals('Match 0 value: ','abba',M.Value);
  280. M:=MS[1];
  281. AssertTrue('Match 0 result: ',M.Success);
  282. AssertEquals('Match 0 value: ','abbba',M.Value);
  283. M:=MS[2];
  284. AssertTrue('Match 0 result: ',M.Success);
  285. AssertEquals('Match 0 value: ','abbbba',M.Value);
  286. end;
  287. procedure TTestRegExp.TestClassMatchesOptions;
  288. var
  289. MS : TMatchCollection;
  290. M : TMatch;
  291. begin
  292. // class function Matches(const aInput, aPattern: TREString; aOptions: TRegExOptions): TMatchCollection; overload; static;
  293. MS:=TRegEx.Matches(TestStr,UpperCase(TestExpr),[roIgnoreCase]);
  294. AssertEquals('Match count',3,MS.Count);
  295. M:=MS[0];
  296. AssertTrue('Match 0 result: ',M.Success);
  297. AssertEquals('Match 0 value: ','abba',M.Value);
  298. M:=MS[1];
  299. AssertTrue('Match 0 result: ',M.Success);
  300. AssertEquals('Match 0 value: ','abbba',M.Value);
  301. M:=MS[2];
  302. AssertTrue('Match 0 result: ',M.Success);
  303. AssertEquals('Match 0 value: ','abbbba',M.Value);
  304. end;
  305. procedure TTestRegExp.TestReplace;
  306. begin
  307. // function Replace(const aInput, aReplacement: TREString): TREString; overload;
  308. RegEx:=TRegex.Create(TestExpr);
  309. AssertEquals('Result','xyz c c c zyx',RegEx.Replace(TestStr,'c'));
  310. end;
  311. function TTestRegExp.DoReplacer(const Match: TMatch): TREString;
  312. begin
  313. Result:='<'+Match.Value+'>';
  314. // Writeln('Replace "',Match.Value,'" -> "',Result,'"')
  315. end;
  316. procedure TTestRegExp.TestReplaceEval;
  317. begin
  318. // function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator): TREString; overload;
  319. RegEx:=TRegex.Create(TestExpr);
  320. AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',RegEx.Replace(TestStr,@DoReplacer));
  321. end;
  322. procedure TTestRegExp.TestReplaceCount;
  323. begin
  324. // function Replace(const aInput, aReplacement: TREString; aCount: Integer): TREString; overload;
  325. RegEx:=TRegex.Create(TestExpr);
  326. AssertEquals('Result','xyz c c abbbba zyx',RegEx.Replace(TestStr,'c',2));
  327. end;
  328. procedure TTestRegExp.TestReplaceEvalCount;
  329. begin
  330. // function Replace(const aInput: TREString; aEvaluator: TMatchEvaluator; aCount: Integer): TREString; overload;
  331. RegEx:=TRegex.Create(TestExpr);
  332. AssertEquals('Result','xyz <abba> <abbba> abbbba zyx',RegEx.Replace(TestStr,@DoReplacer,2));
  333. end;
  334. procedure TTestRegExp.TestClassReplace;
  335. begin
  336. // class function Replace(const aInput, aPattern, aReplacement: TREString): TREString; overload; static;
  337. AssertEquals('Result','xyz c c c zyx',TRegEx.Replace(TestStr,TestExpr,'c'));
  338. end;
  339. procedure TTestRegExp.TestClassReplaceEval;
  340. begin
  341. // class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator): TREString; overload; static;
  342. AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',TRegEx.Replace(TestStr,TestExpr,@DoReplacer));
  343. end;
  344. procedure TTestRegExp.TestClassReplaceOptions;
  345. begin
  346. // class function Replace(const aInput, aPattern, aReplacement: TREString; aOptions: TRegExOptions): TREString; overload; static;
  347. AssertEquals('Result','xyz c c c zyx',TRegEx.Replace(TestStr,UpperCase(TestExpr),'c',[roIgnoreCase]));
  348. end;
  349. procedure TTestRegExp.TestClassReplaceEvalOptions;
  350. begin
  351. // class function Replace(const aInput, aPattern: TREString; aEvaluator: TMatchEvaluator; aOptions: TRegExOptions): TREString; overload; static;
  352. AssertEquals('Result','xyz <abba> <abbba> <abbbba> zyx',TRegEx.Replace(TestStr,UpperCase(TestExpr),@DoReplacer,[roIgnoreCase]));
  353. end;
  354. initialization
  355. RegisterTest(TTestRegExp);
  356. end.