utcregex.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. unit utcregex;
  2. {$mode objfpc}{$H+}
  3. { $DEFINE USEWIDESTRING}
  4. interface
  5. uses
  6. Classes, SysUtils, fpcunit, testutils, testregistry, system.regularexpressionscore;
  7. type
  8. { TTestRegExpCore }
  9. TTestRegExpCore = class(TTestCase)
  10. private
  11. FRegex: TPerlRegEx;
  12. FMatchEventCount : Integer;
  13. FSplitSubject: TStrings;
  14. procedure AssertMatch(const Msg, aMatch: TREString; aPos, aLength: Integer; Groups: array of TREString);
  15. procedure DoMatch(Sender: TObject);
  16. protected
  17. procedure SetUp; override;
  18. procedure TearDown; override;
  19. Property RegEx : TPerlRegEx Read FRegex;
  20. Property SplitSubject : TStrings Read FSplitSubject;
  21. published
  22. Procedure TestHookup;
  23. procedure TestMatch;
  24. procedure TestMatchStart;
  25. procedure TestMatchStop;
  26. procedure TestNamedGroups;
  27. procedure TestReplace;
  28. procedure TestReplaceAll;
  29. procedure TestSplitAll;
  30. procedure TestSplitLimit;
  31. procedure TestInitialCaps;
  32. procedure TestReplaceGroupBackslash;
  33. procedure TestReplaceGroupDollar;
  34. procedure TestReplaceGroupQuoted;
  35. procedure TestReplaceGroupNamed;
  36. procedure TestReplaceGroupNamed2;
  37. procedure TestReplaceGroupNamedInvalidName;
  38. procedure TestReplaceWholeSubject;
  39. procedure TestReplaceLeftOfMatch;
  40. procedure TestReplaceRightOfMatch;
  41. procedure TestReplaceWholeMatch;
  42. procedure TestReplaceLastMatch;
  43. end;
  44. implementation
  45. Const
  46. TestStr = 'xyz abba abbba abbbba zyx';
  47. TestExpr = 'a(b*)a';
  48. procedure TTestRegExpCore.AssertMatch(const Msg, aMatch: TREString; aPos, aLength: Integer; Groups: array of TREString);
  49. var
  50. I : Integer;
  51. begin
  52. AssertTrue(Msg+': Found match',Regex.FoundMatch);
  53. AssertEquals(Msg+': matched text',aMatch,Regex.MatchedText);
  54. AssertEquals(Msg+': offset',aPos,Regex.MatchedOffset);
  55. AssertEquals(Msg+': length',aLength,Regex.MatchedLength);
  56. AssertEquals(Msg+': group count',Length(Groups),Regex.GroupCount);
  57. For I:=1 to Regex.GroupCount do
  58. AssertEquals(Msg+' group['+IntToStr(I)+']',Groups[I-1],Regex.Groups[I]);
  59. end;
  60. procedure TTestRegExpCore.DoMatch(Sender: TObject);
  61. begin
  62. Inc(FMatchEventCount);
  63. end;
  64. procedure TTestRegExpCore.TestMatch;
  65. begin
  66. Regex.subject:=TestStr;
  67. Regex.RegEx:=TestExpr;
  68. AssertTrue('First match found',Regex.Match);
  69. AssertEquals('Match event called',1,FMatchEventCount);
  70. AssertMatch('Match 1','abba',5,4,['bb']);
  71. AssertEquals('Left of match','xyz ',Regex.SubjectLeft);
  72. AssertEquals('Right of match',' abbba abbbba zyx',Regex.SubjectRight);
  73. AssertTrue('Second match found',Regex.MatchAgain);
  74. AssertMatch('Match 2','abbba',10,5,['bbb']);
  75. AssertTrue('Third match found',Regex.MatchAgain);
  76. AssertMatch('Match 3','abbbba',16,6,['bbbb']);
  77. AssertFalse('No more matches',Regex.MatchAgain);
  78. AssertEquals('Match event called',3,FMatchEventCount);
  79. end;
  80. procedure TTestRegExpCore.TestMatchStart;
  81. begin
  82. Regex.subject:=TestStr;
  83. Regex.RegEx:=TestExpr;
  84. Regex.Start:=Pos('abbba',TestStr);
  85. AssertTrue('First match found',Regex.Match);
  86. AssertMatch('Match 1','abbba',10,5,['bbb']);
  87. AssertTrue('Second match found',Regex.MatchAgain);
  88. AssertMatch('Match 3','abbbba',16,6,['bbbb']);
  89. AssertFalse('No more matches',Regex.MatchAgain);
  90. end;
  91. procedure TTestRegExpCore.TestMatchStop;
  92. begin
  93. Regex.subject:=TestStr;
  94. Regex.RegEx:=TestExpr;
  95. Regex.Stop:=4;
  96. AssertFalse('No match found',Regex.Match);
  97. Regex.Stop:=9;
  98. AssertTrue('First match found',Regex.Match);
  99. AssertEquals('Match event called',1,FMatchEventCount);
  100. AssertMatch('Match 1','abba',5,4,['bb']);
  101. AssertFalse('No more matches',Regex.MatchAgain);
  102. AssertEquals('Match event not called again',1,FMatchEventCount);
  103. end;
  104. procedure TTestRegExpCore.TestNamedGroups;
  105. Const
  106. Rec1 = 'Name:"John" Surname:"Doe" Email:"[email protected]"';
  107. Rec2 = 'Name:"Jane" Surname:"Dolina" Email:"[email protected]"';
  108. begin
  109. Regex.Subject:=Rec1+#10+Rec2;
  110. Regex.RegEx:='Name:"(?<Name>[\w]+?)".*?Surname:"(?<Surname>[\w]+?)".*?Email:"(?<Email>\b[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b)"';
  111. AssertTrue('First match found',Regex.Match);
  112. AssertMatch('Match 1',Rec1,1,Length(Rec1),['John','Doe','[email protected]']);
  113. AssertEquals('Nonexisting group','',Regex.NamedGroups['nonexisting']);
  114. AssertEquals('Name group','John',Regex.NamedGroups['Name']);
  115. AssertEquals('Surname group','Doe',Regex.NamedGroups['Surname']);
  116. AssertEquals('Email group','[email protected]',Regex.NamedGroups['Email']);
  117. AssertTrue('Second match found',Regex.MatchAgain);
  118. AssertMatch('Match 2',Rec2,Length(Rec1)+2,Length(Rec2),['Jane','Dolina','[email protected]']);
  119. AssertFalse('No more matches',Regex.MatchAgain);
  120. end;
  121. procedure TTestRegExpCore.TestReplace;
  122. begin
  123. Regex.subject:=TestStr;
  124. Regex.RegEx:=TestExpr;
  125. Regex.Replacement:='c';
  126. AssertTrue('First match found',Regex.Match);
  127. AssertEquals('Replace','c',Regex.Replace);
  128. AssertEquals('Replace result','xyz c abbba abbbba zyx',Regex.Subject);
  129. AssertTrue('Second match found',Regex.MatchAgain);
  130. AssertEquals('Replace 2','c',Regex.Replace);
  131. AssertEquals('Replace 2 result','xyz c c abbbba zyx',Regex.Subject);
  132. AssertTrue('Third match found',Regex.MatchAgain);
  133. AssertEquals('Replace 3','c',Regex.Replace);
  134. AssertEquals('Replace 3 result','xyz c c c zyx',Regex.Subject);
  135. AssertFalse('No more matches',Regex.MatchAgain);
  136. end;
  137. procedure TTestRegExpCore.TestReplaceAll;
  138. begin
  139. Regex.subject:=TestStr;
  140. Regex.RegEx:=TestExpr;
  141. Regex.Replacement:='c';
  142. AssertTrue('Replacements done',Regex.ReplaceAll);
  143. AssertEquals('ReplaceAll result','xyz c c c zyx',Regex.Subject);
  144. end;
  145. procedure TTestRegExpCore.TestReplaceGroupBackslash;
  146. // \n
  147. begin
  148. Regex.subject:='*abba*';
  149. Regex.RegEx:=TestExpr;
  150. Regex.Replacement:='\1';
  151. AssertTrue('Match',Regex.Match);
  152. AssertEquals('ReplaceText','bb',Regex.Replace);
  153. AssertEquals('Result','*bb*',Regex.Subject);
  154. end;
  155. procedure TTestRegExpCore.TestReplaceGroupDollar;
  156. // $N
  157. begin
  158. Regex.subject:='*abba*';
  159. Regex.RegEx:=TestExpr;
  160. Regex.Replacement:='$1';
  161. AssertTrue('Match',Regex.Match);
  162. AssertEquals('ReplaceText','bb',Regex.Replace);
  163. AssertEquals('Result','*bb*',Regex.Subject);
  164. end;
  165. procedure TTestRegExpCore.TestReplaceGroupQuoted;
  166. // \{N}
  167. begin
  168. Regex.subject:='*abba*';
  169. Regex.RegEx:=TestExpr;
  170. Regex.Replacement:='\{1}';
  171. AssertTrue('Match',Regex.Match);
  172. AssertEquals('ReplaceText','bb',Regex.Replace);
  173. AssertEquals('Result','*bb*',Regex.Subject);
  174. end;
  175. procedure TTestRegExpCore.TestReplaceGroupNamed;
  176. // \{name}
  177. begin
  178. Regex.subject:='*abba*';
  179. Regex.RegEx:='a(?<Name>b*?)a';
  180. Regex.Replacement:='\{Name}';
  181. AssertTrue('Match',Regex.Match);
  182. AssertEquals('ReplaceText','bb',Regex.Replace);
  183. AssertEquals('Result','*bb*',Regex.Subject);
  184. end;
  185. procedure TTestRegExpCore.TestReplaceGroupNamed2;
  186. // \{name}
  187. begin
  188. Regex.subject:='*abba*';
  189. Regex.RegEx:='a(?<Name>b*?)a';
  190. Regex.Replacement:='<\{Name}>';
  191. AssertTrue('Match',Regex.Match);
  192. AssertEquals('ReplaceText','<bb>',Regex.Replace);
  193. AssertEquals('Result','*<bb>*',Regex.Subject);
  194. end;
  195. procedure TTestRegExpCore.TestReplaceGroupNamedInvalidName;
  196. // \{name} with invalid name
  197. begin
  198. Regex.subject:='*abba*';
  199. Regex.RegEx:='a(?<Name>b*?)a';
  200. Regex.Replacement:='<\{NameX}>';
  201. AssertTrue('Match',Regex.Match);
  202. AssertEquals('ReplaceText','<>',Regex.Replace);
  203. AssertEquals('Result','*<>*',Regex.Subject);
  204. end;
  205. procedure TTestRegExpCore.TestReplaceWholeSubject;
  206. begin
  207. Regex.subject:='*abba*';
  208. Regex.RegEx:=TestExpr;
  209. Regex.Replacement:='<\_>';
  210. AssertTrue('Match',Regex.Match);
  211. AssertEquals('ReplaceText','<*abba*>',Regex.Replace);
  212. AssertEquals('Result','*<*abba*>*',Regex.Subject);
  213. end;
  214. procedure TTestRegExpCore.TestReplaceLeftOfMatch;
  215. // \`
  216. begin
  217. Regex.subject:='x*abba*';
  218. Regex.RegEx:=TestExpr;
  219. Regex.Replacement:='<\`>';
  220. AssertTrue('Match',Regex.Match);
  221. AssertEquals('ReplaceText','<x*>',Regex.Replace);
  222. AssertEquals('Result','x*<x*>*',Regex.Subject);
  223. end;
  224. procedure TTestRegExpCore.TestReplaceRightOfMatch;
  225. // \'
  226. begin
  227. Regex.subject:='*abba*x';
  228. Regex.RegEx:=TestExpr;
  229. Regex.Replacement:='<\''>';
  230. AssertTrue('Match',Regex.Match);
  231. AssertEquals('ReplaceText','<*x>',Regex.Replace);
  232. AssertEquals('Result','*<*x>*x',Regex.Subject);
  233. end;
  234. procedure TTestRegExpCore.TestReplaceWholeMatch;
  235. // \&
  236. begin
  237. Regex.subject:='*abba*';
  238. Regex.RegEx:=TestExpr;
  239. Regex.Replacement:='<\&>';
  240. AssertTrue('Match',Regex.Match);
  241. AssertEquals('ReplaceText','<abba>',Regex.Replace);
  242. AssertEquals('Result','*<abba>*',Regex.Subject);
  243. end;
  244. procedure TTestRegExpCore.TestReplaceLastMatch;
  245. // \&
  246. begin
  247. Regex.subject:='*abbcca*';
  248. Regex.RegEx:='a(b*)(c*)a';
  249. Regex.Replacement:='<\+>';
  250. AssertTrue('Match',Regex.Match);
  251. AssertEquals('ReplaceText','<cc>',Regex.Replace);
  252. AssertEquals('Result','*<cc>*',Regex.Subject);
  253. end;
  254. procedure TTestRegExpCore.TestSplitAll;
  255. begin
  256. Regex.subject:=TestStr;
  257. Regex.RegEx:='\s';
  258. Regex.Split(SplitSubject,0);
  259. AssertEquals('Count',5,SplitSubject.Count);
  260. AssertEquals('Item 0','xyz',SplitSubject[0]);
  261. AssertEquals('Item 1','abba',SplitSubject[1]);
  262. AssertEquals('Item 2','abbba',SplitSubject[2]);
  263. AssertEquals('Item 3','abbbba',SplitSubject[3]);
  264. AssertEquals('Item 4','zyx',SplitSubject[4]);
  265. end;
  266. procedure TTestRegExpCore.TestSplitLimit;
  267. begin
  268. Regex.subject:=TestStr;
  269. Regex.RegEx:='\s';
  270. Regex.Split(SplitSubject,2);
  271. AssertEquals('Count',2,SplitSubject.Count);
  272. AssertEquals('Item 0','xyz',SplitSubject[0]);
  273. AssertEquals('Item 1','abba abbba abbbba zyx',SplitSubject[1]);
  274. end;
  275. procedure TTestRegExpCore.TestInitialCaps;
  276. begin
  277. AssertEquals('Initialcaps 1','Abc',InitialCaps('aBc'));
  278. AssertEquals('Initialcaps 2',' Abc',InitialCaps(' aBc'));
  279. AssertEquals('Initialcaps 3','Dad Abc',InitialCaps('dAd aBc'));
  280. AssertEquals('Initialcaps 4','Dad Abc ',InitialCaps('dAd aBc '));
  281. end;
  282. procedure TTestRegExpCore.SetUp;
  283. begin
  284. FRegex:=TPerlRegEx.Create;
  285. FRegEx.OnMatch:=@DoMatch;
  286. FMatchEventCount:=0;
  287. FSplitSubject:=TStringList.Create;
  288. end;
  289. procedure TTestRegExpCore.TearDown;
  290. begin
  291. FreeAndNil(FSplitSubject);
  292. FreeAndNil(FRegex);
  293. end;
  294. procedure TTestRegExpCore.TestHookup;
  295. begin
  296. AssertNotNull('Regex',Regex);
  297. AssertTrue('Assigned OnMatch event',Assigned(Regex.OnMatch));
  298. AssertEquals('Match event count',0,FMatchEventCount);
  299. end;
  300. initialization
  301. RegisterTest(TTestRegExpCore);
  302. end.