1// Split-up due to DMD's enormous memory consumption 2 3module std.regex.internal.tests2; 4 5package(std.regex): 6 7import std.conv, std.exception, std.meta, std.range, 8 std.typecons, std.regex; 9 10import std.uni : Escapables; // characters that need escaping 11 12@safe unittest 13{ 14 auto cr = ctRegex!("abc"); 15 assert(bmatch("abc",cr).hit == "abc"); 16 auto cr2 = ctRegex!("ab*c"); 17 assert(bmatch("abbbbc",cr2).hit == "abbbbc"); 18} 19@safe unittest 20{ 21 auto cr3 = ctRegex!("^abc$"); 22 assert(bmatch("abc",cr3).hit == "abc"); 23 auto cr4 = ctRegex!(`\b(a\B[a-z]b)\b`); 24 assert(array(match("azb",cr4).captures) == ["azb", "azb"]); 25} 26 27@safe unittest 28{ 29 auto cr5 = ctRegex!("(?:a{2,4}b{1,3}){1,2}"); 30 assert(bmatch("aaabaaaabbb", cr5).hit == "aaabaaaabbb"); 31 auto cr6 = ctRegex!("(?:a{2,4}b{1,3}){1,2}?"w); 32 assert(bmatch("aaabaaaabbb"w, cr6).hit == "aaab"w); 33} 34 35@safe unittest 36{ 37 auto cr7 = ctRegex!(`\r.*?$`,"sm"); 38 assert(bmatch("abc\r\nxy", cr7).hit == "\r\nxy"); 39 auto greed = ctRegex!("<packet.*?/packet>"); 40 assert(bmatch("<packet>text</packet><packet>text</packet>", greed).hit 41 == "<packet>text</packet>"); 42} 43 44@safe unittest 45{ 46 import std.algorithm.comparison : equal; 47 auto cr8 = ctRegex!("^(a)(b)?(c*)"); 48 auto m8 = bmatch("abcc",cr8); 49 assert(m8); 50 assert(m8.captures[1] == "a"); 51 assert(m8.captures[2] == "b"); 52 assert(m8.captures[3] == "cc"); 53 auto cr9 = ctRegex!("q(a|b)*q"); 54 auto m9 = match("xxqababqyy",cr9); 55 assert(m9); 56 assert(equal(bmatch("xxqababqyy",cr9).captures, ["qababq", "b"])); 57} 58 59@safe unittest 60{ 61 import std.algorithm.comparison : equal; 62 auto rtr = regex("a|b|c"); 63 static ctr = regex("a|b|c"); 64 assert(equal(rtr.ir,ctr.ir)); 65 //CTFE parser BUG is triggered by group 66 //in the middle of alternation (at least not first and not last) 67 static testCT = regex(`abc|(edf)|xyz`); 68 auto testRT = regex(`abc|(edf)|xyz`); 69 assert(equal(testCT.ir,testRT.ir)); 70} 71 72@safe unittest 73{ 74 import std.algorithm.comparison : equal; 75 import std.algorithm.iteration : map; 76 enum cx = ctRegex!"(A|B|C)"; 77 auto mx = match("B",cx); 78 assert(mx); 79 assert(equal(mx.captures, [ "B", "B"])); 80 enum cx2 = ctRegex!"(A|B)*"; 81 assert(match("BAAA",cx2)); 82 83 enum cx3 = ctRegex!("a{3,4}","i"); 84 auto mx3 = match("AaA",cx3); 85 assert(mx3); 86 assert(mx3.captures[0] == "AaA"); 87 enum cx4 = ctRegex!(`^a{3,4}?[a-zA-Z0-9~]{1,2}`,"i"); 88 auto mx4 = match("aaaabc", cx4); 89 assert(mx4); 90 assert(mx4.captures[0] == "aaaab"); 91 auto cr8 = ctRegex!("(a)(b)?(c*)"); 92 auto m8 = bmatch("abcc",cr8); 93 assert(m8); 94 assert(m8.captures[1] == "a"); 95 assert(m8.captures[2] == "b"); 96 assert(m8.captures[3] == "cc"); 97 auto cr9 = ctRegex!(".*$", "gm"); 98 auto m9 = match("First\rSecond", cr9); 99 assert(m9); 100 assert(equal(map!"a.hit"(m9), ["First", "", "Second"])); 101} 102 103@safe unittest 104{ 105 import std.algorithm.comparison : equal; 106 import std.algorithm.iteration : map; 107//global matching 108 void test_body(alias matchFn)() 109 { 110 string s = "a quick brown fox jumps over a lazy dog"; 111 auto r1 = regex("\\b[a-z]+\\b","g"); 112 string[] test; 113 foreach (m; matchFn(s, r1)) 114 test ~= m.hit; 115 assert(equal(test, [ "a", "quick", "brown", "fox", "jumps", "over", "a", "lazy", "dog"])); 116 auto free_reg = regex(` 117 118 abc 119 \s+ 120 " 121 ( 122 [^"]+ 123 | \\ " 124 )+ 125 " 126 z 127 `, "x"); 128 auto m = match(`abc "quoted string with \" inside"z`,free_reg); 129 assert(m); 130 string mails = " hey@you.com no@spam.net "; 131 auto rm = regex(`@(?<=\S+@)\S+`,"g"); 132 assert(equal(map!"a[0]"(matchFn(mails, rm)), ["@you.com", "@spam.net"])); 133 auto m2 = matchFn("First line\nSecond line",regex(".*$","gm")); 134 assert(equal(map!"a[0]"(m2), ["First line", "", "Second line"])); 135 auto m2a = matchFn("First line\nSecond line",regex(".+$","gm")); 136 assert(equal(map!"a[0]"(m2a), ["First line", "Second line"])); 137 auto m2b = matchFn("First line\nSecond line",regex(".+?$","gm")); 138 assert(equal(map!"a[0]"(m2b), ["First line", "Second line"])); 139 debug(std_regex_test) writeln("!!! FReD FLAGS test done "~matchFn.stringof~" !!!"); 140 } 141 test_body!bmatch(); 142 test_body!match(); 143} 144 145//tests for accumulated std.regex issues and other regressions 146@safe unittest 147{ 148 import std.algorithm.comparison : equal; 149 import std.algorithm.iteration : map; 150 void test_body(alias matchFn)() 151 { 152 // https://issues.dlang.org/show_bug.cgi?id=5857 153 //matching goes out of control if ... in (...){x} has .*/.+ 154 auto c = matchFn("axxxzayyyyyzd",regex("(a.*z){2}d")).captures; 155 assert(c[0] == "axxxzayyyyyzd"); 156 assert(c[1] == "ayyyyyz"); 157 auto c2 = matchFn("axxxayyyyyd",regex("(a.*){2}d")).captures; 158 assert(c2[0] == "axxxayyyyyd"); 159 assert(c2[1] == "ayyyyy"); 160 // https://issues.dlang.org/show_bug.cgi?id=2108 161 //greedy vs non-greedy 162 auto nogreed = regex("<packet.*?/packet>"); 163 assert(matchFn("<packet>text</packet><packet>text</packet>", nogreed).hit 164 == "<packet>text</packet>"); 165 auto greed = regex("<packet.*/packet>"); 166 assert(matchFn("<packet>text</packet><packet>text</packet>", greed).hit 167 == "<packet>text</packet><packet>text</packet>"); 168 // https://issues.dlang.org/show_bug.cgi?id=4574 169 //empty successful match still advances the input 170 string[] pres, posts, hits; 171 foreach (m; matchFn("abcabc", regex("","g"))) 172 { 173 pres ~= m.pre; 174 posts ~= m.post; 175 assert(m.hit.empty); 176 177 } 178 auto heads = [ 179 "abcabc", 180 "abcab", 181 "abca", 182 "abc", 183 "ab", 184 "a", 185 "" 186 ]; 187 auto tails = [ 188 "abcabc", 189 "bcabc", 190 "cabc", 191 "abc", 192 "bc", 193 "c", 194 "" 195 ]; 196 assert(pres == array(retro(heads))); 197 assert(posts == tails); 198 // https://issues.dlang.org/show_bug.cgi?id=6076 199 //regression on .* 200 auto re = regex("c.*|d"); 201 auto m = matchFn("mm", re); 202 assert(!m); 203 debug(std_regex_test) writeln("!!! FReD REGRESSION test done "~matchFn.stringof~" !!!"); 204 auto rprealloc = regex(`((.){5}.{1,10}){5}`); 205 auto arr = array(repeat('0',100)); 206 auto m2 = matchFn(arr, rprealloc); 207 assert(m2); 208 assert(collectException( 209 regex(r"^(import|file|binary|config)\s+([^\(]+)\(?([^\)]*)\)?\s*$") 210 ) is null); 211 foreach (ch; [Escapables]) 212 { 213 assert(match(to!string(ch),regex(`[\`~ch~`]`))); 214 assert(!match(to!string(ch),regex(`[^\`~ch~`]`))); 215 assert(match(to!string(ch),regex(`[\`~ch~`-\`~ch~`]`))); 216 } 217 // https://issues.dlang.org/show_bug.cgi?id=7718 218 string strcmd = "./myApp.rb -os OSX -path \"/GIT/Ruby Apps/sec\" -conf 'notimer'"; 219 auto reStrCmd = regex (`(".*")|('.*')`, "g"); 220 assert(equal(map!"a[0]"(matchFn(strcmd, reStrCmd)), 221 [`"/GIT/Ruby Apps/sec"`, `'notimer'`])); 222 } 223 test_body!bmatch(); 224 test_body!match(); 225} 226 227// tests for replace 228@safe unittest 229{ 230 void test(alias matchFn)() 231 { 232 import std.uni : toUpper; 233 234 static foreach (i, v; AliasSeq!(string, wstring, dstring)) 235 {{ 236 auto baz(Cap)(Cap m) 237 if (is(Cap == Captures!(Cap.String))) 238 { 239 return toUpper(m.hit); 240 } 241 alias String = v; 242 assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r")), to!String("c")) 243 == to!String("ack rapacity")); 244 assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r"), "g"), to!String("c")) 245 == to!String("ack capacity")); 246 assert(std.regex.replace!(matchFn)(to!String("noon"), regex(to!String("^n")), to!String("[$&]")) 247 == to!String("[n]oon")); 248 assert(std.regex.replace!(matchFn)( 249 to!String("test1 test2"), regex(to!String(`\w+`),"g"), to!String("$`:$'") 250 ) == to!String(": test2 test1 :")); 251 auto s = std.regex.replace!(baz!(Captures!(String)))(to!String("Strap a rocket engine on a chicken."), 252 regex(to!String("[ar]"), "g")); 253 assert(s == "StRAp A Rocket engine on A chicken."); 254 }} 255 debug(std_regex_test) writeln("!!! Replace test done "~matchFn.stringof~" !!!"); 256 } 257 test!(bmatch)(); 258 test!(match)(); 259} 260 261// tests for splitter 262@safe unittest 263{ 264 import std.algorithm.comparison : equal; 265 auto s1 = ", abc, de, fg, hi, "; 266 auto sp1 = splitter(s1, regex(", *")); 267 auto w1 = ["", "abc", "de", "fg", "hi", ""]; 268 assert(equal(sp1, w1)); 269 270 auto s2 = ", abc, de, fg, hi"; 271 auto sp2 = splitter(s2, regex(", *")); 272 auto w2 = ["", "abc", "de", "fg", "hi"]; 273 274 uint cnt; 275 foreach (e; sp2) 276 { 277 assert(w2[cnt++] == e); 278 } 279 assert(equal(sp2, w2)); 280} 281 282@safe unittest 283{ 284 char[] s1 = ", abc, de, fg, hi, ".dup; 285 auto sp2 = splitter(s1, regex(", *")); 286} 287 288@safe unittest 289{ 290 import std.algorithm.comparison : equal; 291 auto s1 = ", abc, de, fg, hi, "; 292 auto w1 = ["", "abc", "de", "fg", "hi", ""]; 293 assert(equal(split(s1, regex(", *")), w1[])); 294} 295 296// https://issues.dlang.org/show_bug.cgi?id=7141 297@safe unittest 298{ 299 string pattern = `[a\--b]`; 300 assert(match("-", pattern)); 301 assert(match("b", pattern)); 302 string pattern2 = `[&-z]`; 303 assert(match("b", pattern2)); 304} 305 306// https://issues.dlang.org/show_bug.cgi?id=7111 307@safe unittest 308{ 309 assert(match("", regex("^"))); 310} 311 312// https://issues.dlang.org/show_bug.cgi?id=7300 313@safe unittest 314{ 315 assert(!match("a"d, "aa"d)); 316} 317 318// https://issues.dlang.org/show_bug.cgi?id=7551 319@safe unittest 320{ 321 auto r = regex("[]abc]*"); 322 assert("]ab".matchFirst(r).hit == "]ab"); 323 assertThrown(regex("[]")); 324 auto r2 = regex("[]abc--ab]*"); 325 assert("]ac".matchFirst(r2).hit == "]"); 326} 327 328// https://issues.dlang.org/show_bug.cgi?id=7674 329@safe unittest 330{ 331 assert("1234".replace(regex("^"), "$$") == "$1234"); 332 assert("hello?".replace(regex(r"\?", "g"), r"\?") == r"hello\?"); 333 assert("hello?".replace(regex(r"\?", "g"), r"\\?") != r"hello\?"); 334} 335 336// https://issues.dlang.org/show_bug.cgi?id=7679 337@safe unittest 338{ 339 import std.algorithm.comparison : equal; 340 static foreach (S; AliasSeq!(string, wstring, dstring)) 341 {{ 342 enum re = ctRegex!(to!S(r"\.")); 343 auto str = to!S("a.b"); 344 assert(equal(std.regex.splitter(str, re), [to!S("a"), to!S("b")])); 345 assert(split(str, re) == [to!S("a"), to!S("b")]); 346 }} 347} 348 349// https://issues.dlang.org/show_bug.cgi?id=8203 350@safe unittest 351{ 352 string data = " 353 NAME = XPAW01_STA:STATION 354 NAME = XPAW01_STA 355 "; 356 auto uniFileOld = data; 357 auto r = regex( 358 r"^NAME = (?P<comp>[a-zA-Z0-9_]+):*(?P<blk>[a-zA-Z0-9_]*)","gm"); 359 auto uniCapturesNew = match(uniFileOld, r); 360 for (int i = 0; i < 20; i++) 361 foreach (matchNew; uniCapturesNew) {} 362 //a second issue with same symptoms 363 auto r2 = regex(`([��-����-��\-_]+\s*)+(?<=[\s\.,\^])`); 364 match("���������� ����������������������", r2); 365} 366 367// https://issues.dlang.org/show_bug.cgi?id=8637 purity of enforce 368@safe unittest 369{ 370 auto m = match("hello world", regex("world")); 371 enforce(m); 372} 373 374// https://issues.dlang.org/show_bug.cgi?id=8725 375@safe unittest 376{ 377 static italic = regex( r"\* 378 (?!\s+) 379 (.*?) 380 (?!\s+) 381 \*", "gx" ); 382 string input = "this * is* interesting, *very* interesting"; 383 assert(replace(input, italic, "<i>$1</i>") == 384 "this * is* interesting, <i>very</i> interesting"); 385} 386 387// https://issues.dlang.org/show_bug.cgi?id=8349 388@safe unittest 389{ 390 enum peakRegexStr = r"\>(wgEncode.*Tfbs.*\.(?:narrow)|(?:broad)Peak.gz)</a>"; 391 enum peakRegex = ctRegex!(peakRegexStr); 392 //note that the regex pattern itself is probably bogus 393 assert(match(r"\>wgEncode-blah-Tfbs.narrow</a>", peakRegex)); 394} 395 396// https://issues.dlang.org/show_bug.cgi?id=9211 397@safe unittest 398{ 399 import std.algorithm.comparison : equal; 400 auto rx_1 = regex(r"^(\w)*(\d)"); 401 auto m = match("1234", rx_1); 402 assert(equal(m.front, ["1234", "3", "4"])); 403 auto rx_2 = regex(r"^([0-9])*(\d)"); 404 auto m2 = match("1234", rx_2); 405 assert(equal(m2.front, ["1234", "3", "4"])); 406} 407 408// https://issues.dlang.org/show_bug.cgi?id=9280 409@safe unittest 410{ 411 string tomatch = "a!b@c"; 412 static r = regex(r"^(?P<nick>.*?)!(?P<ident>.*?)@(?P<host>.*?)$"); 413 auto nm = match(tomatch, r); 414 assert(nm); 415 auto c = nm.captures; 416 assert(c[1] == "a"); 417 assert(c["nick"] == "a"); 418} 419 420 421// https://issues.dlang.org/show_bug.cgi?id=9579 422@safe unittest 423{ 424 char[] input = ['a', 'b', 'c']; 425 string format = "($1)"; 426 // used to give a compile error: 427 auto re = regex(`(a)`, "g"); 428 auto r = replace(input, re, format); 429 assert(r == "(a)bc"); 430} 431 432// https://issues.dlang.org/show_bug.cgi?id=9634 433@safe unittest 434{ 435 auto re = ctRegex!"(?:a+)"; 436 assert(match("aaaa", re).hit == "aaaa"); 437} 438 439// https://issues.dlang.org/show_bug.cgi?id=10798 440@safe unittest 441{ 442 auto cr = ctRegex!("[abcd--c]*"); 443 auto m = "abc".match(cr); 444 assert(m); 445 assert(m.hit == "ab"); 446} 447 448// https://issues.dlang.org/show_bug.cgi?id=10913 449@system unittest 450{ 451 @system static string foo(const(char)[] s) 452 { 453 return s.dup; 454 } 455 @safe static string bar(const(char)[] s) 456 { 457 return s.dup; 458 } 459 () @system { 460 replace!((a) => foo(a.hit))("blah", regex(`a`)); 461 }(); 462 () @safe { 463 replace!((a) => bar(a.hit))("blah", regex(`a`)); 464 }(); 465} 466 467// https://issues.dlang.org/show_bug.cgi?id=11262 468@safe unittest 469{ 470 enum reg = ctRegex!(r",", "g"); 471 auto str = "This,List"; 472 str = str.replace(reg, "-"); 473 assert(str == "This-List"); 474} 475 476// https://issues.dlang.org/show_bug.cgi?id=11775 477@safe unittest 478{ 479 assert(collectException(regex("a{1,0}"))); 480} 481 482// https://issues.dlang.org/show_bug.cgi?id=11839 483@safe unittest 484{ 485 import std.algorithm.comparison : equal; 486 assert(regex(`(?P<var1>\w+)`).namedCaptures.equal(["var1"])); 487 assert(collectException(regex(`(?P<1>\w+)`))); 488 assert(regex(`(?P<v1>\w+)`).namedCaptures.equal(["v1"])); 489 assert(regex(`(?P<__>\w+)`).namedCaptures.equal(["__"])); 490 assert(regex(`(?P<��>\w+)`).namedCaptures.equal(["��"])); 491} 492 493// https://issues.dlang.org/show_bug.cgi?id=12076 494@safe unittest 495{ 496 auto RE = ctRegex!(r"(?<!x[a-z]+)\s([a-z]+)"); 497 string s = "one two"; 498 auto m = match(s, RE); 499} 500 501// https://issues.dlang.org/show_bug.cgi?id=12105 502@safe unittest 503{ 504 auto r = ctRegex!`.*?(?!a)`; 505 assert("aaab".matchFirst(r).hit == "aaa"); 506 auto r2 = ctRegex!`.*(?!a)`; 507 assert("aaab".matchFirst(r2).hit == "aaab"); 508} 509 510// https://issues.dlang.org/show_bug.cgi?id=11784 511@safe unittest 512{ 513 assert("abcdefghijklmnopqrstuvwxyz" 514 .matchFirst("[a-z&&[^aeiuo]]").hit == "b"); 515} 516 517// https://issues.dlang.org/show_bug.cgi?id=12366 518@safe unittest 519{ 520 auto re = ctRegex!(`^((?=(xx+?)\2+$)((?=\2+$)(?=(x+)(\4+$))\5){2})*x?$`); 521 assert("xxxxxxxx".match(re).empty); 522 assert(!"xxxx".match(re).empty); 523} 524 525// https://issues.dlang.org/show_bug.cgi?id=12582 526@safe unittest 527{ 528 auto r = regex(`(?P<a>abc)`); 529 assert(collectException("abc".matchFirst(r)["b"])); 530} 531 532// https://issues.dlang.org/show_bug.cgi?id=12691 533@safe unittest 534{ 535 assert(bmatch("e@", "^([a-z]|)*$").empty); 536 assert(bmatch("e@", ctRegex!`^([a-z]|)*$`).empty); 537} 538 539// https://issues.dlang.org/show_bug.cgi?id=12713 540@safe unittest 541{ 542 assertThrown(regex("[[a-z]([a-z]|(([[a-z])))")); 543} 544 545// https://issues.dlang.org/show_bug.cgi?id=12747 546@safe unittest 547{ 548 assertThrown(regex(`^x(\1)`)); 549 assertThrown(regex(`^(x(\1))`)); 550 assertThrown(regex(`^((x)(?=\1))`)); 551} 552 553// https://issues.dlang.org/show_bug.cgi?id=13532 554version (none) // TODO: revist once we have proper benchmark framework 555@safe unittest 556{ 557 import std.datetime.stopwatch : StopWatch, AutoStart; 558 import std.math.algebraic : abs; 559 import std.conv : to; 560 enum re1 = ctRegex!`[0-9][0-9]`; 561 immutable static re2 = ctRegex!`[0-9][0-9]`; 562 immutable iterations = 1_000_000; 563 size_t result1 = 0, result2 = 0; 564 auto sw = StopWatch(AutoStart.yes); 565 foreach (_; 0 .. iterations) 566 { 567 result1 += matchFirst("12345678", re1).length; 568 } 569 const staticTime = sw.peek(); 570 sw.reset(); 571 foreach (_; 0 .. iterations) 572 { 573 result2 += matchFirst("12345678", re2).length; 574 } 575 const enumTime = sw.peek(); 576 assert(result1 == result2); 577 auto ratio = 1.0 * enumTime.total!"usecs" / staticTime.total!"usecs"; 578 // enum is faster or the diff is less < 30% 579 assert(ratio < 1.0 || abs(ratio - 1.0) < 0.75, 580 "enum regex to static regex ratio "~to!string(ratio)); 581} 582 583// https://issues.dlang.org/show_bug.cgi?id=14504 584@safe unittest 585{ 586 auto p = ctRegex!("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?" ~ 587 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); 588} 589 590// https://issues.dlang.org/show_bug.cgi?id=14529 591@safe unittest 592{ 593 auto ctPat2 = regex(r"^[CDF]$", "i"); 594 foreach (v; ["C", "c", "D", "d", "F", "f"]) 595 assert(matchAll(v, ctPat2).front.hit == v); 596} 597 598// https://issues.dlang.org/show_bug.cgi?id=14615 599@safe unittest 600{ 601 import std.array : appender; 602 import std.regex : replaceFirst, replaceFirstInto, regex; 603 import std.stdio : writeln; 604 605 auto example = "Hello, world!"; 606 auto pattern = regex("^Hello, (bug)"); // won't find this one 607 auto result = replaceFirst(example, pattern, "$1 Sponge Bob"); 608 assert(result == "Hello, world!"); // Ok. 609 610 auto sink = appender!string; 611 replaceFirstInto(sink, example, pattern, "$1 Sponge Bob"); 612 assert(sink.data == "Hello, world!"); 613 replaceAllInto(sink, example, pattern, "$1 Sponge Bob"); 614 assert(sink.data == "Hello, world!Hello, world!"); 615} 616 617// https://issues.dlang.org/show_bug.cgi?id=15573 618@safe unittest 619{ 620 auto rx = regex("[c d]", "x"); 621 assert("a b".matchFirst(rx)); 622} 623 624// https://issues.dlang.org/show_bug.cgi?id=15864 625@safe unittest 626{ 627 regex(`(<a (?:(?:\w+=\"[^"]*\")?\s*)*href="\.\.?)"`); 628} 629 630@safe unittest 631{ 632 auto r = regex("(?# comment)abc(?# comment2)"); 633 assert("abc".matchFirst(r)); 634 assertThrown(regex("(?#...")); 635} 636 637// https://issues.dlang.org/show_bug.cgi?id=17075 638@safe unittest 639{ 640 enum titlePattern = `<title>(.+)</title>`; 641 static titleRegex = ctRegex!titlePattern; 642 string input = "<title>" ~ "<".repeat(100_000).join; 643 assert(input.matchFirst(titleRegex).empty); 644} 645 646// https://issues.dlang.org/show_bug.cgi?id=17212 647@safe unittest 648{ 649 auto r = regex(" [a] ", "x"); 650 assert("a".matchFirst(r)); 651} 652 653// https://issues.dlang.org/show_bug.cgi?id=17157 654@safe unittest 655{ 656 import std.algorithm.comparison : equal; 657 auto ctr = ctRegex!"(a)|(b)|(c)|(d)"; 658 auto r = regex("(a)|(b)|(c)|(d)", "g"); 659 auto s = "--a--b--c--d--"; 660 auto outcomes = [ 661 ["a", "a", "", "", ""], 662 ["b", "", "b", "", ""], 663 ["c", "", "", "c", ""], 664 ["d", "", "", "", "d"] 665 ]; 666 assert(equal!equal(s.matchAll(ctr), outcomes)); 667 assert(equal!equal(s.bmatch(r), outcomes)); 668} 669 670// https://issues.dlang.org/show_bug.cgi?id=17667 671@safe unittest 672{ 673 import std.algorithm.searching : canFind; 674 void willThrow(T, size_t line = __LINE__)(T arg, string msg) 675 { 676 auto e = collectException(regex(arg)); 677 assert(e.msg.canFind(msg), to!string(line) ~ ": " ~ e.msg); 678 } 679 willThrow([r".", r"[\(\{[\]\}\)]"], "no matching ']' found while parsing character class"); 680 willThrow([r"[\", r"123"], "no matching ']' found while parsing character class"); 681 willThrow([r"[a-", r"123"], "no matching ']' found while parsing character class"); 682 willThrow([r"[a-\", r"123"], "no matching ']' found while parsing character class"); 683 willThrow([r"\", r"123"], "invalid escape sequence"); 684} 685 686// https://issues.dlang.org/show_bug.cgi?id=17668 687@safe unittest 688{ 689 import std.algorithm.searching; 690 auto e = collectException!RegexException(regex(q"<[^]>")); 691 assert(e.msg.canFind("no operand for '^'"), e.msg); 692} 693 694// https://issues.dlang.org/show_bug.cgi?id=17673 695@safe unittest 696{ 697 string str = `<">`; 698 string[] regexps = ["abc", "\"|x"]; 699 auto regexp = regex(regexps); 700 auto c = matchFirst(str, regexp); 701 assert(c); 702 assert(c.whichPattern == 2); 703} 704 705// https://issues.dlang.org/show_bug.cgi?id=18692 706@safe unittest 707{ 708 auto rx = regex("()()()"); 709 auto ma = "".matchFirst(rx); 710 auto ma2 = ma; 711 ma = ma2; 712 assert(ma[1] == ""); 713} 714