1
2 #include <reflex/pcre2matcher.h>
3
4 // #define INTERACTIVE // for interactive mode testing
5 // #define UTF // for native PCRE2_UTF+PCRE2_UCP matching, only matches ASCII and Unicode not binary 0-255
6
7 #ifdef UTF
8 #define MATCHER PCRE2UTFMatcher
9 #else
10 #define MATCHER PCRE2Matcher
11 #endif
12
banner(const char * title)13 static void banner(const char *title)
14 {
15 int i;
16 printf("\n\n/");
17 for (i = 0; i < 78; i++)
18 putchar('*');
19 printf("\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", title, "");
20 for (i = 0; i < 78; i++)
21 putchar('*');
22 printf("/\n\n");
23 }
24
error(const char * text)25 static void error(const char *text)
26 {
27 std::cout << "FAILED: " << text << std::endl;
28 exit(EXIT_FAILURE);
29 }
30
31 using namespace reflex;
32
33 class WrappedMatcher : public MATCHER {
34 public:
WrappedMatcher()35 WrappedMatcher() : MATCHER(), source(0)
36 { }
37 private:
wrap()38 virtual bool wrap()
39 {
40 switch (source++)
41 {
42 case 0: in = "Hello World!";
43 return true;
44 case 1: in = "How now brown cow.";
45 return true;
46 case 2: in = "An apple a day.";
47 return true;
48 }
49 return false;
50 }
51 int source;
52 };
53
54 struct Test {
55 const char *pattern;
56 const char *popts;
57 const char *mopts;
58 const char *cstring;
59 size_t accepts[32];
60 };
61
62 Test tests[] = {
63 { "ab", "", "", "ab", { 1 } },
64 { "ab", "", "", "abab", { 1, 1 } },
65 { "ab|xy", "", "", "abxy", { 1, 2 } },
66 { "a(p|q)z", "", "", "apzaqz", { 1, 1 } },
67 // DFA edge compaction test (only applicable to RE/flex)
68 { "[a-cg-ik]z|d|[e-g]|j|y|[x-z]|.|\\n", "", "", "azz", { 1, 6 } },
69 // POSIX character classes
70 {
71 "\\x7E-"
72 "[[:space:]]-"
73 "[[:xdigit:]]-"
74 "[[:cntrl:]]-"
75 "[[:print:]]-"
76 "[[:alnum:]]-"
77 "[[:alpha:]]-"
78 "[[:blank:]]-"
79 "[[:digit:]]-"
80 "[[:graph:]]-"
81 "[[:lower:]]-"
82 "[[:punct:]]-"
83 "[[:upper:]]-"
84 "[[:word:]]", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
85 {
86 "\\x7E-"
87 "\\p{Space}-"
88 "\\p{XDigit}-"
89 "\\p{Cntrl}-"
90 "\\p{Print}-"
91 "\\p{Alnum}-"
92 "\\p{Alpha}-"
93 "\\p{Blank}-"
94 "\\p{Digit}-"
95 "\\p{Graph}-"
96 "\\p{Lower}-"
97 "\\p{Punct}-"
98 "\\p{Upper}-"
99 "\\p{Word}", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
100 // Pattern option i
101 { "(?i:abc)", "", "", "abcABC", { 1, 1 } },
102 { "(?i)abc|xyz", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
103 { "(?i:abc)|xyz", "", "", "abcABCxyz", { 1, 1, 2 } },
104 { "(?i:abc)|(?i:xyz)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
105 { "(?i)abc|(?-i:xyz)|(?-i:XYZ)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 3 } },
106 { "(?i:abc(?-i:xyz))|ABCXYZ", "", "", "abcxyzABCxyzABCXYZ", { 1, 1, 2 } },
107 // Pattern option x
108 { "(?x) a\tb\n c | ( xy ) z ?", "", "", "abcxy", { 1, 2 } },
109 { "(?x: a b\n c)", "", "", "abc", { 1 } },
110 { "(?x) a b c\n|\n# COMMENT\n x y z", "", "", "abcxyz", { 1, 2 } },
111 // { "(?x) a b c\n|\n/* COMMENT\n*/ x y z", "", "", "abcxyz", { 1, 2 } }, // PCRE2 does not support /*...*/
112 { "(?# test option (?x:... )(?x: a b c)|x y z", "", "", "abcx y z", { 1, 2 } },
113 // Pattern option s
114 { "(?s).", "", "", "a\n", { 1, 1 } },
115 { "(?s:.)", "", "", "a\n", { 1, 1 } },
116 { "(?s).", "", "", "a\n", { 1, 1 } },
117 // Anchors \A, \Z, ^, and $
118 { "\\Aa\\Z", "", "", "a", { 1 } },
119 { "^a$", "", "m", "a", { 1 } },
120 { "(?m)^a$|\\n", "m", "", "a\na", { 1, 2, 1 } },
121 { "(?m)^a|a$|a|\\n", "m", "", "aa\naaa", { 1, 2, 4, 1, 3, 2 } },
122 { "(?m)^ab$|^ab|ab$|ab|\\Aa\\Z|\\Aa|a\\Z|^a$|^a|a$|a|\\n", "m", "", "a\na\naa\naaa\nab\nabab\nababab\na", { 6, 12, 8, 12, 9, 10, 12, 9, 11, 10, 12, 1, 12, 2, 3, 12, 2, 4, 3, 12, 7 } }, // CHANGED for Perl matching
123 // Optional X?
124 { "a?z", "", "", "azz", { 1, 1 } },
125 // Closure X*
126 { "a*z", "", "", "azaazz", { 1, 1, 1 } },
127 // Positive closure X+
128 { "a+z", "", "", "azaaz", { 1, 1 } },
129 // Combi ? * +
130 { "a?b+|a", "", "", "baba", { 1, 1, 2 } },
131 { "a*b+|a", "", "", "baabaa", { 1, 1, 2, 2 } },
132 // Iterations {n,m}
133 { "ab{2}", "", "", "abbabb", { 1, 1 } },
134 { "ab{2,3}", "", "", "abbabbb", { 1, 1 } },
135 { "ab{2,}", "", "", "abbabbbabbbb", { 1, 1, 1 } },
136 { "ab{0,}", "", "", "a", { 1 } },
137 { "(ab{0,2}c){2}", "", "", "abbcacabcabc", { 1, 1 } },
138 // Lazy optional X?
139 { "(a|b)?\?a", "", "", "aaba", { 1, 1, 1 } },
140 { "a(a|b)?\?(?=a|ab)|ac", "", "", "aababac", { 1, 1, 1, 2 } },
141 { "(a|b)?\?(a|b)?\?aa", "", "", "baaaabbaa", { 1, 1, 1 } },
142 { "(a|b)?\?(a|b)?\?(a|b)?\?aaa", "", "", "baaaaaa", { 1, 1 } },
143 { "a?\?b?a", "", "", "aba", { 1, 1 } }, // 'a' 'ba'
144 { "a?\?b?b", "", "", "abb", { 1 } }, // 'abb'
145 // Lazy closure X*
146 { "a*?a", "", "", "aaaa", { 1, 1, 1, 1 } },
147 { "a|a*?|b", "", "", "aab", { 1, 1, 3 } }, // CHANGED for Perl matching
148 { "(a|bb)*?abb", "", "", "abbbbabb", { 1, 1 } },
149 { "ab*?|b", "", "", "ab", { 1, 2 } },
150 { "(ab)*?|b", "", "", "b", { 2 } },
151 { "a(ab)*?|b", "", "", "ab", { 1, 2 } },
152 { "(a|b)*?a|c?", "", "", "bbaaac", { 1, 1, 1, 2 } },
153 { "a(a|b)*?a", "", "", "aaaba", { 1, 1 } },
154 { "a(a|b)*?a?\?|b", "", "", "aaaba", { 1, 1, 1, 2, 1 } },
155 { "a(a|b)*?a?", "", "", "aa", { 1 } },
156 { "a(a|b)*?a|a", "", "", "aaaba", { 1, 1 } },
157 { "a(a|b)*?a|a?", "", "", "aaaba", { 1, 1 } },
158 { "a(a|b)*?a|a?\?", "", "", "aaaba", { 1, 1 } },
159 { "a(a|b)*?a|aa?", "", "", "aaaba", { 1, 1 } },
160 { "a(a|b)*?a|aa?\?", "", "", "aaaba", { 1, 1 } },
161 { "ab(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
162 { "(a|b)(a|b)*?a|a", "", "", "aaabaa", { 1, 1, 2 } },
163 { "(ab|cd)(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
164 { "(ab)(ab)*?a|b", "", "", "abababa", { 1, 2, 1 } },
165 { "a?(a|b)*?a", "", "", "aaababa", { 1, 1, 1 } },
166 { "(?m)^(a|b)*?a", "m", "", "bba", { 1 } },
167 { "(?m)(a|b)*?a$", "m", "", "bba", { 1 } },
168 { "(?m)^(a|b)*?|b", "m", "", "ab", { 1, 2 } },
169 // Lazy positive closure X+
170 { "a+?a", "", "", "aaaa", { 1, 1 } },
171 { "(a|b)+?", "", "", "ab", { 1, 1 } },
172 { "(a|b)+?a", "", "", "bbaaa", { 1, 1 } },
173 { "(a|b)+?a|c?", "", "", "bbaaa", { 1, 1 } },
174 { "(ab|cd)+?ab|d?", "", "", "cdcdababab", { 1, 1 } },
175 { "(ab)+?a|b", "", "", "abababa", { 1, 2, 1 } },
176 { "(ab)+?ac", "", "", "ababac", { 1 } },
177 { "ABB*?|ab+?|A|a", "", "", "ABab", { 1, 2 } },
178 { "(a|b)+?a|a", "", "", "bbaaa", { 1, 1 } },
179 { "(?m)^(a|b)+?a", "m", "", "abba", { 1 } },
180 { "(?m)(a|b)+?a$", "m", "", "abba", { 1 } },
181 // Lazy iterations {n,m}
182 { "(a|b){0,3}?aaa", "", "", "baaaaaa", { 1, 1 } },
183 { "(a|b){1,3}?aaa", "", "", "baaaaaaa", { 1, 1 } },
184 { "(a|b){1,3}?aaa", "", "", "bbbaaaaaaa", { 1, 1 } },
185 { "(ab|cd){0,3}?ababab", "", "", "cdabababababab", { 1, 1 } },
186 { "(ab|cd){1,3}?ababab", "", "", "cdababababababab", { 1, 1 } },
187 { "(a|b){1,}?a|a", "", "", "bbaaa", { 1, 1 } },
188 { "(a|b){2,}?a|aa", "", "", "bbbaaaa", { 1, 1 } },
189 // Bracket lists
190 { "[a-z]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
191 { "[a-d-z]", "", "", "abcd-z", { 1, 1, 1, 1, 1, 1 } },
192 { "[-z]", "", "", "-z", { 1, 1 } },
193 { "[z-]", "", "", "-z", { 1, 1 } },
194 { "[--z]", "", "", "-az", { 1, 1, 1 } },
195 { "[ --]", "", "", " +-", { 1, 1, 1 } },
196 { "[^a-z]", "", "", "A", { 1 } },
197 { "[[:alpha:]]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
198 { "[\\p{Alpha}]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
199 { "[][]", "", "", "[]", { 1, 1 } },
200 // Lookahead
201 { "a(?=bc)|ab(?=d)|bc|d", "", "", "abcdabd", { 1, 3, 4, 2, 4 } },
202 // { "[ab]+(?=ab)|-|ab", "", "", "aaab-bbab", { 1, 3, 2, 1, 3 } }, // has trailing context (undefined as per POSIX)
203 { "(?m)a(?=b?)|bc", "m", "", "aabc", { 1, 1, 2 } },
204 { "(?m)a(?=\\nb)|a|^b|\\n", "m", "", "aa\nb\n", { 2, 1, 4, 3, 4 } },
205 { "(?m)^a(?=b$)|b|\\n", "m", "", "ab\n", { 1, 2, 3 } },
206 { "(?m)a(?=\n)|a|\\n", "m", "", "aa\n", { 2, 1, 3 } },
207 { "(?m)^( +(?=a)|b)|a|\\n", "m", "", " a\n a\nb\n", { 1, 2, 3, 1, 2, 3, 1, 3 } },
208 // Word boundaries \<, \>, \b, and \B
209 { "\\<a\\>|\\<a|a\\>|a|-", "", "", "a-aaa", { 1, 5, 2, 4, 3 } },
210 { "\\<.*\\>", "", "", "abc def", { 1 } },
211 { "\\<.*\\>|-", "", "", "abc-", { 1, 2 } },
212 { "\\b.*\\b|-", "", "", "abc-", { 1, 2 } },
213 { "-|\\<.*\\>", "", "", "-abc-", { 1, 2, 1 } },
214 { "-|\\b.*\\b", "", "", "-abc-", { 1, 2, 1 } },
215 { "(-|a)\\<(-|a)\\>(-|a)", "", "", "-a-", { 1 } },
216 { "(-|a)\\b(-|a)\\b(-|a)", "", "", "-a-a-a", { 1, 1 } },
217 { "(-|a)\\B(-|a)\\B(-|a)", "", "", "---aaa", { 1, 1 } },
218 { "\\<(-|a)(-|a)\\>| ", "", "", "aa aa", { 1, 2, 1 } },
219 { "\\b(-|a)(-|a)\\b| ", "", "", "aa aa", { 1, 2, 1 } },
220 { "\\B(-|a)(-|a)\\B|b|#", "", "", "baab#--#", { 2, 1, 2, 3, 1, 3 } },
221 { "\\<.*ab\\>|[ab]*|-|\\n", "", "", "-aaa-aaba-aab-\n-aaa", { 3, 1, 3, 4, 3, 2 } },
222 { "-\\b(-|a)(-|a)\\b", "", "", "-aa", { 1 } },
223 { "a\\b(-|a)(-|a)\\b", "", "", "a-a", { 1 } },
224 { "a?\\>(-|a)(-|a)\\b| ", "", "", "a-a-a", { 1, 1 } },
225 { "\\b(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
226 { "(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
227 { "a?\\b(-|a)(-|a)\\b| ", "", "", "a-a", { 1 } },
228 { "-(?=\\<a\\>)|-|a|b", "", "", "-a-ab", { 1, 3, 2, 3, 4 } },
229 // Unicode
230 { "(©)+", "", "", "©", { 1 } },
231 { NULL, NULL, NULL, NULL, { } }
232 };
233
main()234 int main()
235 {
236 banner("PATTERN TESTS");
237 for (const Test *test = tests; test->pattern != NULL; ++test)
238 {
239 std::string regex;
240 try
241 {
242 regex = MATCHER::convert(test->pattern, convert_flag::recap);
243 }
244 catch (const regex_error& e)
245 {
246 std::cerr << e.what();
247 }
248 std::cout << regex << std::endl;
249 std::string pattern(regex);
250 MATCHER matcher(pattern, test->cstring, test->mopts);
251 #ifdef INTERACTIVE
252 matcher.interactive(); // test with blk=1
253 #endif
254 printf("Test \"%s\" against \"%s\"\n", test->pattern, test->cstring);
255 if (*test->popts)
256 printf("With pattern options \"%s\"\n", test->popts);
257 if (*test->mopts)
258 printf("With matcher options \"%s\"\n", test->mopts);
259 size_t i = 0;
260 while (matcher.scan())
261 {
262 printf(" At %zu,%zu;[%zu,%zu]: \"%s\" matches pattern %zu\n", matcher.lineno(), matcher.columno(), matcher.first(), matcher.last(), matcher.text(), matcher.accept());
263 if (matcher.accept() != test->accepts[i])
264 break;
265 ++i;
266 }
267 if (matcher.accept() != 0 || test->accepts[i] != 0 || !matcher.at_end())
268 {
269 if (!matcher.at_end())
270 printf("ERROR: remaining input rest = '%s'\n", matcher.rest());
271 else
272 printf("ERROR: accept = %zu text = '%s'\n", matcher.accept(), matcher.text());
273 exit(1);
274 }
275 printf("OK\n\n");
276 }
277 MATCHER pattern1("(\\w+)|(\\W)");
278 MATCHER pattern2(MATCHER::convert("\\<.*\\>"));
279 MATCHER pattern3(" ");
280 MATCHER pattern4("[ \\t]+");
281 MATCHER pattern5("\\b");
282 MATCHER pattern6("");
283 MATCHER pattern7("[[:alpha:]]");
284 MATCHER pattern8("\\w+");
285 MATCHER pattern9(MATCHER::convert("(?u:\\p{L})"));
286
287 MATCHER matcher(pattern1);
288 std::string test;
289 //
290 banner("TEST FIND");
291 //
292 matcher.pattern(pattern8);
293 matcher.input("an apple a day");
294 test = "";
295 while (matcher.find())
296 {
297 std::cout << matcher.text() << "/";
298 test.append(matcher.text()).append("/");
299 }
300 std::cout << std::endl;
301 if (test != "an/apple/a/day/")
302 error("find results");
303 //
304 matcher.pattern(pattern5);
305 matcher.reset("N");
306 matcher.input("a a");
307 test = "";
308 while (matcher.find())
309 {
310 std::cout << matcher.text() << "/";
311 test.append(matcher.text()).append("/");
312 }
313 std::cout << std::endl;
314 if (test != "///")
315 error("find with nullable results");
316 matcher.reset("");
317 //
318 matcher.pattern(pattern6);
319 matcher.reset("N");
320 matcher.input("a a");
321 test = "";
322 while (matcher.find())
323 {
324 std::cout << matcher.text() << "/";
325 test.append(matcher.text()).append("/");
326 }
327 std::cout << std::endl;
328 if (test != "///")
329 error("find with nullable results");
330 matcher.reset("");
331 //
332 banner("TEST SPLIT");
333 //
334 matcher.pattern(pattern3);
335 matcher.input("ab c d");
336 test = "";
337 while (matcher.split())
338 {
339 std::cout << matcher.text() << "/";
340 test.append(matcher.text()).append("/");
341 }
342 std::cout << std::endl;
343 if (test != "ab/c//d/")
344 error("split results");
345 //
346 matcher.pattern(pattern3);
347 matcher.input("ab c d ");
348 test = "";
349 while (matcher.split())
350 {
351 std::cout << matcher.text() << "/";
352 test.append(matcher.text()).append("/");
353 }
354 std::cout << std::endl;
355 if (test != "ab/c//d//")
356 error("split results");
357 //
358 matcher.pattern(pattern4);
359 matcher.input("ab c d");
360 test = "";
361 while (matcher.split())
362 {
363 std::cout << matcher.text() << "/";
364 test.append(matcher.text()).append("/");
365 }
366 std::cout << std::endl;
367 if (test != "ab/c/d/")
368 error("split results");
369 //
370 matcher.pattern(pattern5);
371 matcher.input("ab c d");
372 test = "";
373 while (matcher.split())
374 {
375 std::cout << matcher.text() << "/";
376 test.append(matcher.text()).append("/");
377 }
378 std::cout << std::endl;
379 if (test != "/ab/ /c/ /d//")
380 error("split results");
381 //
382 matcher.pattern(pattern6);
383 matcher.input("ab c d");
384 test = "";
385 while (matcher.split())
386 {
387 std::cout << matcher.text() << "/";
388 test.append(matcher.text()).append("/");
389 }
390 std::cout << std::endl;
391 if (test != "/a/b/ /c/ / /d//")
392 error("split results");
393 //
394 matcher.pattern(pattern6);
395 matcher.input("");
396 test = "";
397 while (matcher.split())
398 {
399 std::cout << matcher.text() << "/";
400 test.append(matcher.text()).append("/");
401 }
402 std::cout << std::endl;
403 if (test != "/")
404 error("split results");
405 //
406 matcher.pattern(pattern7);
407 matcher.input("a-b");
408 test = "";
409 while (matcher.split())
410 {
411 std::cout << matcher.text() << "/";
412 test.append(matcher.text()).append("/");
413 }
414 std::cout << std::endl;
415 if (test != "/-//")
416 error("split results");
417 //
418 matcher.pattern(pattern7);
419 matcher.input("a");
420 test = "";
421 while (matcher.split())
422 {
423 std::cout << matcher.text() << "/";
424 test.append(matcher.text()).append("/");
425 }
426 std::cout << std::endl;
427 if (test != "//")
428 error("split results");
429 //
430 matcher.pattern(pattern7);
431 matcher.input("-");
432 test = "";
433 while (matcher.split())
434 {
435 std::cout << matcher.text() << "/";
436 test.append(matcher.text()).append("/");
437 }
438 std::cout << std::endl;
439 if (test != "-/")
440 error("split results");
441 //
442 matcher.pattern(pattern4);
443 matcher.input("ab c d");
444 int n = 2; // split 2
445 while (n-- && matcher.split())
446 std::cout << matcher.text() << "/";
447 std::cout << std::endl << "REST = " << matcher.rest() << std::endl;
448 //
449 banner("TEST INPUT/UNPUT");
450 //
451 matcher.pattern(pattern2);
452 matcher.input("ab c d");
453 while (!matcher.at_end())
454 std::cout << (char)matcher.input() << "/";
455 std::cout << std::endl;
456 //
457 matcher.pattern(pattern2);
458 matcher.input("ab c d");
459 test = "";
460 while (true)
461 {
462 if (matcher.scan())
463 {
464 std::cout << matcher.text() << "/";
465 test.append(matcher.text()).append("/");
466 }
467 else if (!matcher.at_end())
468 {
469 std::cout << (char)matcher.input() << "?/";
470 test.append("?/");
471 }
472 else
473 {
474 break;
475 }
476 }
477 std::cout << std::endl;
478 if (test != "ab c d/")
479 error("input");
480 //
481 matcher.pattern(pattern7);
482 matcher.input("ab c d");
483 test = "";
484 while (true)
485 {
486 if (matcher.scan())
487 {
488 std::cout << matcher.text() << "/";
489 test.append(matcher.text()).append("/");
490 }
491 else if (!matcher.at_end())
492 {
493 std::cout << (char)matcher.input() << "?/";
494 test.append("?/");
495 }
496 else
497 {
498 break;
499 }
500 }
501 std::cout << std::endl;
502 if (test != "a/b/?/c/?/?/d/")
503 error("input");
504 //
505 matcher.pattern(pattern7);
506 matcher.input("ab c d");
507 matcher.unput('a');
508 test = "";
509 while (true)
510 {
511 if (matcher.scan())
512 {
513 std::cout << matcher.text() << "/";
514 test.append(matcher.text()).append("/");
515 if (*matcher.text() == 'b')
516 matcher.unput('c');
517 }
518 else if (!matcher.at_end())
519 {
520 std::cout << (char)matcher.input() << "?/";
521 }
522 else
523 {
524 break;
525 }
526 }
527 std::cout << std::endl;
528 if (test != "a/a/b/c/c/d/")
529 error("unput");
530 //
531 matcher.pattern(pattern9);
532 matcher.input("ab c d");
533 matcher.wunput(L'ä');
534 test = "";
535 while (true)
536 {
537 if (matcher.scan())
538 {
539 std::cout << matcher.text() << "/";
540 test.append(matcher.text()).append("/");
541 if (*matcher.text() == 'b')
542 matcher.wunput(L'ç');
543 }
544 else if (!matcher.at_end())
545 {
546 std::cout << (char)matcher.winput() << "?/";
547 }
548 else
549 {
550 break;
551 }
552 }
553 std::cout << std::endl;
554 if (test != "ä/a/b/ç/c/d/")
555 {
556 std::cout << test << '\n';
557 error("wunput");
558 }
559 //
560 banner("TEST WRAP");
561 //
562 WrappedMatcher wrapped_matcher;
563 wrapped_matcher.pattern(pattern8);
564 test = "";
565 while (wrapped_matcher.find())
566 {
567 std::cout << wrapped_matcher.text() << "/";
568 test.append(wrapped_matcher.text()).append("/");
569 }
570 std::cout << std::endl;
571 if (test != "Hello/World/How/now/brown/cow/An/apple/a/day/")
572 error("wrap");
573 //
574 banner("TEST REST");
575 //
576 matcher.pattern(pattern8);
577 matcher.input("abc def xyz");
578 test = "";
579 if (matcher.find())
580 {
581 std::cout << matcher.text() << "/";
582 test.append(matcher.text()).append("/");
583 }
584 std::cout << std::endl;
585 if (test != "abc/" || strcmp(matcher.rest(), " def xyz") != 0)
586 error("rest");
587 //
588 banner("TEST SKIP");
589 //
590 matcher.pattern(pattern8);
591 matcher.input("abc \ndef xyz");
592 test = "";
593 if (matcher.scan())
594 {
595 std::cout << matcher.text() << "/";
596 test.append(matcher.text()).append("/");
597 matcher.skip('\n');
598 }
599 if (matcher.scan())
600 {
601 std::cout << matcher.text() << "/";
602 test.append(matcher.text()).append("/");
603 matcher.skip('\n');
604 }
605 //
606 matcher.input("abc ¶def¶");
607 test = "";
608 if (matcher.scan())
609 {
610 std::cout << matcher.text() << "/";
611 test.append(matcher.text()).append("/");
612 matcher.skip(L'¶');
613 }
614 if (matcher.scan())
615 {
616 std::cout << matcher.text() << "/";
617 test.append(matcher.text()).append("/");
618 matcher.skip(L'¶');
619 }
620 //
621 matcher.input("abc xxydef xx");
622 test = "";
623 if (matcher.scan())
624 {
625 std::cout << matcher.text() << "/";
626 test.append(matcher.text()).append("/");
627 matcher.skip("xy");
628 }
629 if (matcher.scan())
630 {
631 std::cout << matcher.text() << "/";
632 test.append(matcher.text()).append("/");
633 matcher.skip("xy");
634 }
635 std::cout << std::endl;
636 if (test != "abc/def/")
637 error("skip");
638 //
639 #ifdef WITH_SPAN
640 banner("TEST SPAN");
641 //
642 matcher.pattern(pattern8);
643 matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
644 test = "";
645 while (matcher.find())
646 {
647 std::cout << matcher.span() << "/";
648 test.append(matcher.span()).append("/");
649 }
650 std::cout << std::endl;
651 if (test != "##a#b#c##/def##/##ghi/##xyz/")
652 error("span");
653 //
654 banner("TEST LINE");
655 //
656 matcher.pattern(pattern8);
657 matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
658 test = "";
659 while (matcher.find())
660 {
661 std::cout << matcher.line() << "/";
662 test.append(matcher.line()).append("/");
663 }
664 std::cout << std::endl;
665 if (test != "##a#b#c##/##a#b#c##/##a#b#c##/def##/##ghi/##xyz/")
666 error("line");
667 #endif
668 //
669 banner("TEST MORE");
670 //
671 matcher.pattern(pattern7);
672 matcher.input("abc");
673 test = "";
674 while (matcher.scan())
675 {
676 std::cout << matcher.text() << "/";
677 matcher.more();
678 test.append(matcher.text()).append("/");
679 }
680 std::cout << std::endl;
681 if (test != "a/ab/abc/")
682 error("more");
683 //
684 banner("TEST LESS");
685 //
686 matcher.pattern(pattern1);
687 matcher.input("abc");
688 test = "";
689 while (matcher.scan())
690 {
691 matcher.less(1);
692 std::cout << matcher.text() << "/";
693 test.append(matcher.text()).append("/");
694 }
695 std::cout << std::endl;
696 if (test != "a/b/c/")
697 error("less");
698 //
699 banner("TEST MATCHES");
700 //
701 if (MATCHER("\\w+", "hello").matches()) // on the fly string matching
702 std::cout << "OK";
703 else
704 error("match results");
705 std::cout << std::endl;
706 if (MATCHER("\\d", "0").matches())
707 std::cout << "OK";
708 else
709 error("match results");
710 std::cout << std::endl;
711 //
712 matcher.pattern(pattern1);
713 matcher.input("abc");
714 if (matcher.matches())
715 std::cout << "OK";
716 else
717 error("match results");
718 std::cout << std::endl;
719 //
720 matcher.pattern(pattern2);
721 matcher.input("abc");
722 if (matcher.matches())
723 std::cout << "OK";
724 else
725 error("match results");
726 std::cout << std::endl;
727 //
728 matcher.pattern(pattern6);
729 matcher.input("");
730 if (matcher.matches())
731 std::cout << "OK";
732 else
733 error("match results");
734 std::cout << std::endl;
735 //
736 matcher.pattern(pattern2);
737 matcher.input("---");
738 if (!matcher.matches())
739 std::cout << "OK";
740 else
741 error("match results");
742 std::cout << std::endl;
743 //
744 banner("DONE");
745 //
746 return 0;
747 }
748