3 int static_total_tests
= 0;
4 int static_failed_tests
= 0;
7 void FAIL (usize line
, const(char)* str) {
8 import core
.stdc
.stdio
: printf
;
9 printf("Fail on line %d: [%s]\n", line
, str);
10 ++static_failed_tests
;
14 void ASSERT(usize ln
=__LINE__
) (bool cond
) {
16 if (!cond
) FAIL(ln
, "fucked");
20 // regex must have exactly one bracket pair
21 char[] slre_replace (const(char)[] regex
, const(char)[] buf
, const(char)[] sub) {
25 auto n
= Slre
.matchFirst(regex
, buf
[], cap
[]);
31 // if some bytes were skipped, add them verbatim
32 if (cap
[0].ofs
> 0) s
~= buf
[0..cap
[0].ofs
];
35 // if we have some bytes left, add them verbatim
36 if (cap
[0].ofs
+cap
[0].len
< n
) {
37 //{ import std.stdio; writeln("n=", n, "; ofs=", cap[0].ofs, "; len=", cap[0].len, "; end=", cap[0].ofs+cap[0].len); }
38 s
~= buf
[cap
[0].ofs
+cap
[0].len
..n
];
47 Slre
.Capture
[10] caps
;
49 int slre_match (const(char)[] re
, const(char)[] str, int strlen
, Slre
.Capture
* caps
, int capslen
, int flags
) {
50 return Slre
.matchFirst(re
, str[0..strlen
], caps
[0..capslen
], flags
);
54 ASSERT(slre_match("$", "abcd", 4, null, 0, 0) == 4);
55 ASSERT(slre_match("^", "abcd", 4, null, 0, 0) == 0);
56 ASSERT(slre_match("x|^", "abcd", 4, null, 0, 0) == 0);
57 ASSERT(slre_match("x|$", "abcd", 4, null, 0, 0) == 4);
58 ASSERT(slre_match("x", "abcd", 4, null, 0, 0) == Slre
.Result
.NoMatch
);
59 ASSERT(slre_match(".", "abcd", 4, null, 0, 0) == 1);
60 ASSERT(slre_match("^.*\\\\.*$", "c:\\Tools", 8, null, 0, Slre
.Flag
.IgnoreCase
) == 8);
61 ASSERT(slre_match("\\", "a", 1, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
62 ASSERT(slre_match("\\x", "a", 1, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
63 ASSERT(slre_match("\\x1", "a", 1, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
64 ASSERT(slre_match("\\x20", " ", 1, null, 0, 0) == 1);
66 ASSERT(slre_match("^.+$", "", 0, null, 0, 0) == Slre
.Result
.NoMatch
);
67 ASSERT(slre_match("^(.+)$", "", 0, null, 0, 0) == Slre
.Result
.NoMatch
);
68 ASSERT(slre_match("^([\\+-]?)([\\d]+)$", "+", 1, caps
.ptr
, 10, Slre
.Flag
.IgnoreCase
) == Slre
.Result
.NoMatch
);
69 ASSERT(slre_match("^([\\+-]?)([\\d]+)$", "+27", 3, caps
.ptr
, 10, Slre
.Flag
.IgnoreCase
) == 3);
70 ASSERT(caps
[0].ptr
== "+");
71 ASSERT(caps
[1].ptr
== "27");
73 ASSERT(slre_match("tel:\\+(\\d+[\\d-]+\\d)", "tel:+1-201-555-0123;a=b", 23, caps
.ptr
, 10, 0) == 19);
74 ASSERT(caps
[0].ptr
== "1-201-555-0123");
77 ASSERT(slre_match("[abc]", "1c2", 3, null, 0, 0) == 2);
78 ASSERT(slre_match("[abc]", "1C2", 3, null, 0, 0) == Slre
.Result
.NoMatch
);
79 ASSERT(slre_match("[abc]", "1C2", 3, null, 0, Slre
.Flag
.IgnoreCase
) == 2);
80 ASSERT(slre_match("[.2]", "1C2", 3, null, 0, 0) == 1);
81 ASSERT(slre_match("[\\S]+", "ab cd", 5, null, 0, 0) == 2);
82 ASSERT(slre_match("[\\S]+\\s+[tyc]*", "ab cd", 5, null, 0, 0) == 4);
83 ASSERT(slre_match("[\\d]", "ab cd", 5, null, 0, 0) == Slre
.Result
.NoMatch
);
84 ASSERT(slre_match("[^\\d]", "ab cd", 5, null, 0, 0) == 1);
85 ASSERT(slre_match("[^\\d]+", "abc123", 6, null, 0, 0) == 3);
86 ASSERT(slre_match("[1-5]+", "123456789", 9, null, 0, 0) == 5);
87 ASSERT(slre_match("[1-5a-c]+", "123abcdef", 9, null, 0, 0) == 6);
88 ASSERT(slre_match("[1-5a-]+", "123abcdef", 9, null, 0, 0) == 4);
89 ASSERT(slre_match("[1-5a-]+", "123a--2oo", 9, null, 0, 0) == 7);
90 ASSERT(slre_match("[htps]+://", "https://", 8, null, 0, 0) == 8);
91 ASSERT(slre_match("[^\\s]+", "abc def", 7, null, 0, 0) == 3);
92 ASSERT(slre_match("[^fc]+", "abc def", 7, null, 0, 0) == 2);
93 ASSERT(slre_match("[^d\\sf]+", "abc def", 7, null, 0, 0) == 3);
95 // flags: case sensitivity
96 ASSERT(slre_match("FO", "foo", 3, null, 0, 0) == Slre
.Result
.NoMatch
);
97 ASSERT(slre_match("FO", "foo", 3, null, 0, Slre
.Flag
.IgnoreCase
) == 2);
98 ASSERT(slre_match("(?m)FO", "foo", 3, null, 0, 0) == Slre
.Result
.UnexpectedQuantifier
);
99 ASSERT(slre_match("(?m)x", "foo", 3, null, 0, 0) == Slre
.Result
.UnexpectedQuantifier
);
101 ASSERT(slre_match("fo", "foo", 3, null, 0, 0) == 2);
102 ASSERT(slre_match(".+", "foo", 3, null, 0, 0) == 3);
103 ASSERT(slre_match(".+k", "fooklmn", 7, null, 0, 0) == 4);
104 ASSERT(slre_match(".+k.", "fooklmn", 7, null, 0, 0) == 5);
105 ASSERT(slre_match("p+", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
106 ASSERT(slre_match("ok", "fooklmn", 7, null, 0, 0) == 4);
107 ASSERT(slre_match("lmno", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
108 ASSERT(slre_match("mn.", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
109 ASSERT(slre_match("o", "fooklmn", 7, null, 0, 0) == 2);
110 ASSERT(slre_match("^o", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
111 ASSERT(slre_match("^", "fooklmn", 7, null, 0, 0) == 0);
112 ASSERT(slre_match("n$", "fooklmn", 7, null, 0, 0) == 7);
113 ASSERT(slre_match("n$k", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
114 ASSERT(slre_match("l$", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
115 ASSERT(slre_match(".$", "fooklmn", 7, null, 0, 0) == 7);
116 ASSERT(slre_match("a?", "fooklmn", 7, null, 0, 0) == 0);
117 ASSERT(slre_match("^a*CONTROL", "CONTROL", 7, null, 0, 0) == 7);
118 ASSERT(slre_match("^[a]*CONTROL", "CONTROL", 7, null, 0, 0) == 7);
119 ASSERT(slre_match("^(a*)CONTROL", "CONTROL", 7, null, 0, 0) == 7);
120 ASSERT(slre_match("^(a*)?CONTROL", "CONTROL", 7, null, 0, 0) == 7);
122 ASSERT(slre_match("\\_", "abc", 3, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
123 ASSERT(slre_match("+", "fooklmn", 7, null, 0, 0) == Slre
.Result
.UnexpectedQuantifier
);
124 ASSERT(slre_match("()+", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
125 ASSERT(slre_match("\\x", "12", 2, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
126 ASSERT(slre_match("\\xhi", "12", 2, null, 0, 0) == Slre
.Result
.InvalidMetaChar
);
127 ASSERT(slre_match("\\x20", "_ J", 3, null, 0, 0) == 2);
128 ASSERT(slre_match("\\x4A", "_ J", 3, null, 0, 0) == 3);
129 ASSERT(slre_match("\\d+", "abc123def", 9, null, 0, 0) == 6);
131 // balancing brackets
132 ASSERT(slre_match("(x))", "fooklmn", 7, null, 0, 0) == Slre
.Result
.UnbalancedBrackets
);
133 ASSERT(slre_match("(", "fooklmn", 7, null, 0, 0) == Slre
.Result
.UnbalancedBrackets
);
135 ASSERT(slre_match("klz?mn", "fooklmn", 7, null, 0, 0) == 7);
136 ASSERT(slre_match("fa?b", "fooklmn", 7, null, 0, 0) == Slre
.Result
.NoMatch
);
138 // brackets & capturing
139 ASSERT(slre_match("^(te)", "tenacity subdues all", 20, caps
.ptr
, 10, 0) == 2);
140 ASSERT(slre_match("(bc)", "abcdef", 6, caps
.ptr
, 10, 0) == 3);
141 ASSERT(slre_match(".(d.)", "abcdef", 6, caps
.ptr
, 10, 0) == 5);
142 ASSERT(slre_match(".(d.)\\)?", "abcdef", 6, caps
.ptr
, 10, 0) == 5);
143 ASSERT(caps
[0].ptr
== "de");
144 ASSERT(slre_match("(.+)", "123", 3, caps
.ptr
, 10, 0) == 3);
145 ASSERT(slre_match("(2.+)", "123", 3, caps
.ptr
, 10, 0) == 3);
146 ASSERT(caps
[0].ptr
== "23");
147 ASSERT(slre_match("(.+2)", "123", 3, caps
.ptr
, 10, 0) == 2);
148 ASSERT(caps
[0].ptr
== "12");
149 ASSERT(slre_match("(.*(2.))", "123", 3, caps
.ptr
, 10, 0) == 3);
150 ASSERT(slre_match("(.)(.)", "123", 3, caps
.ptr
, 10, 0) == 2);
151 ASSERT(slre_match("(\\d+)\\s+(\\S+)", "12 hi", 5, caps
.ptr
, 10, 0) == 5);
152 ASSERT(slre_match("ab(cd)+ef", "abcdcdef", 8, null, 0, 0) == 8);
153 ASSERT(slre_match("ab(cd)*ef", "abcdcdef", 8, null, 0, 0) == 8);
154 ASSERT(slre_match("ab(cd)+?ef", "abcdcdef", 8, null, 0, 0) == 8);
155 ASSERT(slre_match("ab(cd)+?.", "abcdcdef", 8, null, 0, 0) == 5);
156 ASSERT(slre_match("ab(cd)?", "abcdcdef", 8, null, 0, 0) == 4);
157 ASSERT(slre_match("a(b)(cd)", "abcdcdef", 8, caps
.ptr
, 1, 0) == Slre
.Result
.CapsArrayTooSmall
);
158 ASSERT(slre_match("(.+/\\d+\\.\\d+)\\.jpg$", "/foo/bar/12.34.jpg", 18, caps
.ptr
, 1, 0) == 18);
159 ASSERT(slre_match("(ab|cd).*\\.(xx|yy)", "ab.yy", 5, null, 0, 0) == 5);
160 ASSERT(slre_match(".*a", "abcdef", 6, null, 0, 0) == 1);
161 ASSERT(slre_match("(.+)c", "abcdef", 6, null, 0, 0) == 3);
162 ASSERT(slre_match("\\n", "abc\ndef", 7, null, 0, 0) == 4);
163 ASSERT(slre_match("b.\\s*\\n", "aa\r\nbb\r\ncc\r\n\r\n", 14, caps
.ptr
, 10, 0) == 8);
165 // greedy vs non-greedy
166 ASSERT(slre_match(".+c", "abcabc", 6, null, 0, 0) == 6);
167 ASSERT(slre_match(".+?c", "abcabc", 6, null, 0, 0) == 3);
168 ASSERT(slre_match(".*?c", "abcabc", 6, null, 0, 0) == 3);
169 ASSERT(slre_match(".*c", "abcabc", 6, null, 0, 0) == 6);
170 ASSERT(slre_match("bc.d?k?b+", "abcabc", 6, null, 0, 0) == 5);
173 ASSERT(slre_match("|", "abc", 3, null, 0, 0) == 0);
174 ASSERT(slre_match("|.", "abc", 3, null, 0, 0) == 1);
175 ASSERT(slre_match("x|y|b", "abc", 3, null, 0, 0) == 2);
176 ASSERT(slre_match("k(xx|yy)|ca", "abcabc", 6, null, 0, 0) == 4);
177 ASSERT(slre_match("k(xx|yy)|ca|bc", "abcabc", 6, null, 0, 0) == 3);
178 ASSERT(slre_match("(|.c)", "abc", 3, caps
.ptr
, 10, 0) == 3);
179 ASSERT(caps
[0].ptr
== "bc");
180 ASSERT(slre_match("a|b|c", "a", 1, null, 0, 0) == 1);
181 ASSERT(slre_match("a|b|c", "b", 1, null, 0, 0) == 1);
182 ASSERT(slre_match("a|b|c", "c", 1, null, 0, 0) == 1);
183 ASSERT(slre_match("a|b|c", "d", 1, null, 0, 0) == Slre
.Result
.NoMatch
);
185 // optional match at the end of the string
186 ASSERT(slre_match("^.*c.?$", "abc", 3, null, 0, 0) == 3);
187 ASSERT(slre_match("^.*C.?$", "abc", 3, null, 0, Slre
.Flag
.IgnoreCase
) == 3);
188 ASSERT(slre_match("bk?", "ab", 2, null, 0, 0) == 2);
189 ASSERT(slre_match("b(k?)", "ab", 2, null, 0, 0) == 2);
190 ASSERT(slre_match("b[k-z]*", "ab", 2, null, 0, 0) == 2);
191 ASSERT(slre_match("ab(k|z|y)*", "ab", 2, null, 0, 0) == 2);
192 ASSERT(slre_match("[b-z].*", "ab", 2, null, 0, 0) == 2);
193 ASSERT(slre_match("(b|z|u).*", "ab", 2, null, 0, 0) == 2);
194 ASSERT(slre_match("ab(k|z|y)?", "ab", 2, null, 0, 0) == 2);
195 ASSERT(slre_match(".*", "ab", 2, null, 0, 0) == 2);
196 ASSERT(slre_match(".*$", "ab", 2, null, 0, 0) == 2);
197 ASSERT(slre_match("a+$", "aa", 2, null, 0, 0) == 2);
198 ASSERT(slre_match("a*$", "aa", 2, null, 0, 0) == 2);
199 ASSERT(slre_match( "a+$" ,"Xaa", 3, null, 0, 0) == 3);
200 ASSERT(slre_match( "a*$" ,"Xaa", 3, null, 0, 0) == 3);
203 ASSERT(slre_match("[a-h]+", "abcdefghxxx", 11, null, 0, 0) == 8);
204 ASSERT(slre_match("[A-H]+", "ABCDEFGHyyy", 11, null, 0, 0) == 8);
205 ASSERT(slre_match("[a-h]+", "ABCDEFGHyyy", 11, null, 0, 0) == Slre
.Result
.NoMatch
);
206 ASSERT(slre_match("[A-H]+", "abcdefghyyy", 11, null, 0, 0) == Slre
.Result
.NoMatch
);
207 ASSERT(slre_match("[a-h]+", "ABCDEFGHyyy", 11, null, 0, Slre
.Flag
.IgnoreCase
) == 8);
208 ASSERT(slre_match("[A-H]+", "abcdefghyyy", 11, null, 0, Slre
.Flag
.IgnoreCase
) == 8);
211 import core
.stdc
.stdio
: printf
;
212 // example: HTTP request
213 string request
= " GET /index.html HTTP/1.0\r\n\r\n";
216 if (slre_match("^\\s*(\\S+)\\s+(\\S+)\\s+HTTP/(\\d)\\.(\\d)", request
, cast(int)request
.length
, caps
.ptr
, 4, 0) > 0) {
217 printf("Method: [%.*s], URI: [%.*s]\n", caps
[0].len
, caps
[0].ptr
.ptr
, caps
[1].len
, caps
[1].ptr
.ptr
);
219 printf("Error parsing [%.*s]\n", cast(uint)request
.length
, request
.ptr
);
221 ASSERT(caps
[1].ptr
== "/index.html");
225 import core
.stdc
.stdio
: printf
;
226 // example: string replacement
227 auto s
= slre_replace("({{.+?}})", "Good morning, {{foo}}. How are you, {{bar}}?", "Bob");
228 printf("%.*s\n", cast(uint)s
.length
, s
.ptr
);
229 ASSERT(s
== "Good morning, Bob. How are you, Bob?");
233 import core
.stdc
.stdio
: printf
;
234 // example: find all URLs in a string
235 string
str = "<img src=\"HTTPS://FOO.COM/x?b#c=tab1\"/> <a href=\"http://cesanta.com\">some link</a>";
236 string regex
= "((https?://)[^\\s/'\"<>]+/?[^\\s'\"<>]*)";
238 int i
, j
= 0, str_len
= cast(int)str.length
;
239 while (j
< str_len
&& (i
= slre_match(regex
, str[j
..$], str_len
-j
, caps
.ptr
, 2, Slre
.Flag
.IgnoreCase
)) > 0) {
240 printf("Found URL: [%.*s]\n", caps
[0].len
, caps
[0].ptr
.ptr
);
246 // example more complex regular expression
247 string
str = "aa 1234 xy\nxyz";
248 string regex
= "aa ([0-9]*) *([x-z]*)\\s+xy([yz])";
250 ASSERT(slre_match(regex
, str, cast(int)str.length
, caps
.ptr
, 3, 0) > 0);
251 ASSERT(caps
[0].len
== 4);
252 ASSERT(caps
[1].len
== 2);
253 ASSERT(caps
[2].len
== 1);
254 ASSERT(caps
[2].ptr
[0] == 'z');
258 import core
.stdc
.stdio
: printf
;
259 printf("Unit test %s (total test: %d, failed tests: %d)\n",
260 static_failed_tests
> 0 ?
"FAILED".ptr
: "PASSED".ptr
,
261 static_total_tests
, static_failed_tests
);
264 //return static_failed_tests == 0 ? EXIT_SUCCESS : EXIT_FAILURE;