github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/regexp/all_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package regexp 6 7 import ( 8 "reflect" 9 "strings" 10 "testing" 11 ) 12 13 var good_re = []string{ 14 ``, 15 `.`, 16 `^.$`, 17 `a`, 18 `a*`, 19 `a+`, 20 `a?`, 21 `a|b`, 22 `a*|b*`, 23 `(a*|b)(c*|d)`, 24 `[a-z]`, 25 `[a-abc-c\-\]\[]`, 26 `[a-z]+`, 27 `[abc]`, 28 `[^1234]`, 29 `[^\n]`, 30 `\!\\`, 31 } 32 33 type stringError struct { 34 re string 35 err string 36 } 37 38 var bad_re = []stringError{ 39 {`*`, "missing argument to repetition operator: `*`"}, 40 {`+`, "missing argument to repetition operator: `+`"}, 41 {`?`, "missing argument to repetition operator: `?`"}, 42 {`(abc`, "missing closing ): `(abc`"}, 43 {`abc)`, "unexpected ): `abc)`"}, 44 {`x[a-z`, "missing closing ]: `[a-z`"}, 45 {`[z-a]`, "invalid character class range: `z-a`"}, 46 {`abc\`, "trailing backslash at end of expression"}, 47 {`a**`, "invalid nested repetition operator: `**`"}, 48 {`a*+`, "invalid nested repetition operator: `*+`"}, 49 {`\x`, "invalid escape sequence: `\\x`"}, 50 } 51 52 func compileTest(t *testing.T, expr string, error string) *Regexp { 53 re, err := Compile(expr) 54 if error == "" && err != nil { 55 t.Error("compiling `", expr, "`; unexpected error: ", err.Error()) 56 } 57 if error != "" && err == nil { 58 t.Error("compiling `", expr, "`; missing error") 59 } else if error != "" && !strings.Contains(err.Error(), error) { 60 t.Error("compiling `", expr, "`; wrong error: ", err.Error(), "; want ", error) 61 } 62 return re 63 } 64 65 func TestGoodCompile(t *testing.T) { 66 for i := 0; i < len(good_re); i++ { 67 compileTest(t, good_re[i], "") 68 } 69 } 70 71 func TestBadCompile(t *testing.T) { 72 for i := 0; i < len(bad_re); i++ { 73 compileTest(t, bad_re[i].re, bad_re[i].err) 74 } 75 } 76 77 func matchTest(t *testing.T, test *FindTest) { 78 re := compileTest(t, test.pat, "") 79 if re == nil { 80 return 81 } 82 m := re.MatchString(test.text) 83 if m != (len(test.matches) > 0) { 84 t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0) 85 } 86 // now try bytes 87 m = re.Match([]byte(test.text)) 88 if m != (len(test.matches) > 0) { 89 t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0) 90 } 91 } 92 93 func TestMatch(t *testing.T) { 94 for _, test := range findTests { 95 matchTest(t, &test) 96 } 97 } 98 99 func matchFunctionTest(t *testing.T, test *FindTest) { 100 m, err := MatchString(test.pat, test.text) 101 if err == nil { 102 return 103 } 104 if m != (len(test.matches) > 0) { 105 t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0) 106 } 107 } 108 109 func TestMatchFunction(t *testing.T) { 110 for _, test := range findTests { 111 matchFunctionTest(t, &test) 112 } 113 } 114 115 type ReplaceTest struct { 116 pattern, replacement, input, output string 117 } 118 119 var replaceTests = []ReplaceTest{ 120 // Test empty input and/or replacement, with pattern that matches the empty string. 121 {"", "", "", ""}, 122 {"", "x", "", "x"}, 123 {"", "", "abc", "abc"}, 124 {"", "x", "abc", "xaxbxcx"}, 125 126 // Test empty input and/or replacement, with pattern that does not match the empty string. 127 {"b", "", "", ""}, 128 {"b", "x", "", ""}, 129 {"b", "", "abc", "ac"}, 130 {"b", "x", "abc", "axc"}, 131 {"y", "", "", ""}, 132 {"y", "x", "", ""}, 133 {"y", "", "abc", "abc"}, 134 {"y", "x", "abc", "abc"}, 135 136 // Multibyte characters -- verify that we don't try to match in the middle 137 // of a character. 138 {"[a-c]*", "x", "\u65e5", "x\u65e5x"}, 139 {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"}, 140 141 // Start and end of a string. 142 {"^[a-c]*", "x", "abcdabc", "xdabc"}, 143 {"[a-c]*$", "x", "abcdabc", "abcdx"}, 144 {"^[a-c]*$", "x", "abcdabc", "abcdabc"}, 145 {"^[a-c]*", "x", "abc", "x"}, 146 {"[a-c]*$", "x", "abc", "x"}, 147 {"^[a-c]*$", "x", "abc", "x"}, 148 {"^[a-c]*", "x", "dabce", "xdabce"}, 149 {"[a-c]*$", "x", "dabce", "dabcex"}, 150 {"^[a-c]*$", "x", "dabce", "dabce"}, 151 {"^[a-c]*", "x", "", "x"}, 152 {"[a-c]*$", "x", "", "x"}, 153 {"^[a-c]*$", "x", "", "x"}, 154 155 {"^[a-c]+", "x", "abcdabc", "xdabc"}, 156 {"[a-c]+$", "x", "abcdabc", "abcdx"}, 157 {"^[a-c]+$", "x", "abcdabc", "abcdabc"}, 158 {"^[a-c]+", "x", "abc", "x"}, 159 {"[a-c]+$", "x", "abc", "x"}, 160 {"^[a-c]+$", "x", "abc", "x"}, 161 {"^[a-c]+", "x", "dabce", "dabce"}, 162 {"[a-c]+$", "x", "dabce", "dabce"}, 163 {"^[a-c]+$", "x", "dabce", "dabce"}, 164 {"^[a-c]+", "x", "", ""}, 165 {"[a-c]+$", "x", "", ""}, 166 {"^[a-c]+$", "x", "", ""}, 167 168 // Other cases. 169 {"abc", "def", "abcdefg", "defdefg"}, 170 {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"}, 171 {"abc", "", "abcdabc", "d"}, 172 {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"}, 173 {"abc", "d", "", ""}, 174 {"abc", "d", "abc", "d"}, 175 {".+", "x", "abc", "x"}, 176 {"[a-c]*", "x", "def", "xdxexfx"}, 177 {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"}, 178 {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"}, 179 180 // Substitutions 181 {"a+", "($0)", "banana", "b(a)n(a)n(a)"}, 182 {"a+", "(${0})", "banana", "b(a)n(a)n(a)"}, 183 {"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"}, 184 {"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"}, 185 {"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, world"}, 186 {"hello, (.+)", "goodbye, $1x", "hello, world", "goodbye, "}, 187 {"hello, (.+)", "goodbye, ${1}x", "hello, world", "goodbye, worldx"}, 188 {"hello, (.+)", "<$0><$1><$2><$3>", "hello, world", "<hello, world><world><><>"}, 189 {"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, world!"}, 190 {"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, world"}, 191 {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "hihihi"}, 192 {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "byebyebye"}, 193 {"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", ""}, 194 {"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "hiyz"}, 195 {"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $x"}, 196 {"a+", "${oops", "aaa", "${oops"}, 197 {"a+", "$$", "aaa", "$"}, 198 {"a+", "$", "aaa", "$"}, 199 200 // Substitution when subexpression isn't found 201 {"(x)?", "$1", "123", "123"}, 202 {"abc", "$1", "123", "123"}, 203 } 204 205 var replaceLiteralTests = []ReplaceTest{ 206 // Substitutions 207 {"a+", "($0)", "banana", "b($0)n($0)n($0)"}, 208 {"a+", "(${0})", "banana", "b(${0})n(${0})n(${0})"}, 209 {"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"}, 210 {"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"}, 211 {"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, ${1}"}, 212 {"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, $noun!"}, 213 {"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, ${noun}"}, 214 {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "$x$x$x"}, 215 {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "$x$x$x"}, 216 {"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", "$xyz"}, 217 {"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "${x}yz"}, 218 {"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $$x"}, 219 {"a+", "${oops", "aaa", "${oops"}, 220 {"a+", "$$", "aaa", "$$"}, 221 {"a+", "$", "aaa", "$"}, 222 } 223 224 type ReplaceFuncTest struct { 225 pattern string 226 replacement func(string) string 227 input, output string 228 } 229 230 var replaceFuncTests = []ReplaceFuncTest{ 231 {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"}, 232 {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"}, 233 {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"}, 234 } 235 236 func TestReplaceAll(t *testing.T) { 237 for _, tc := range replaceTests { 238 re, err := Compile(tc.pattern) 239 if err != nil { 240 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) 241 continue 242 } 243 actual := re.ReplaceAllString(tc.input, tc.replacement) 244 if actual != tc.output { 245 t.Errorf("%q.ReplaceAllString(%q,%q) = %q; want %q", 246 tc.pattern, tc.input, tc.replacement, actual, tc.output) 247 } 248 // now try bytes 249 actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement))) 250 if actual != tc.output { 251 t.Errorf("%q.ReplaceAll(%q,%q) = %q; want %q", 252 tc.pattern, tc.input, tc.replacement, actual, tc.output) 253 } 254 } 255 } 256 257 func TestReplaceAllLiteral(t *testing.T) { 258 // Run ReplaceAll tests that do not have $ expansions. 259 for _, tc := range replaceTests { 260 if strings.Contains(tc.replacement, "$") { 261 continue 262 } 263 re, err := Compile(tc.pattern) 264 if err != nil { 265 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) 266 continue 267 } 268 actual := re.ReplaceAllLiteralString(tc.input, tc.replacement) 269 if actual != tc.output { 270 t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q", 271 tc.pattern, tc.input, tc.replacement, actual, tc.output) 272 } 273 // now try bytes 274 actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement))) 275 if actual != tc.output { 276 t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q", 277 tc.pattern, tc.input, tc.replacement, actual, tc.output) 278 } 279 } 280 281 // Run literal-specific tests. 282 for _, tc := range replaceLiteralTests { 283 re, err := Compile(tc.pattern) 284 if err != nil { 285 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) 286 continue 287 } 288 actual := re.ReplaceAllLiteralString(tc.input, tc.replacement) 289 if actual != tc.output { 290 t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q", 291 tc.pattern, tc.input, tc.replacement, actual, tc.output) 292 } 293 // now try bytes 294 actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement))) 295 if actual != tc.output { 296 t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q", 297 tc.pattern, tc.input, tc.replacement, actual, tc.output) 298 } 299 } 300 } 301 302 func TestReplaceAllFunc(t *testing.T) { 303 for _, tc := range replaceFuncTests { 304 re, err := Compile(tc.pattern) 305 if err != nil { 306 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) 307 continue 308 } 309 actual := re.ReplaceAllStringFunc(tc.input, tc.replacement) 310 if actual != tc.output { 311 t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q", 312 tc.pattern, tc.input, tc.replacement, actual, tc.output) 313 } 314 // now try bytes 315 actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) })) 316 if actual != tc.output { 317 t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q", 318 tc.pattern, tc.input, tc.replacement, actual, tc.output) 319 } 320 } 321 } 322 323 type MetaTest struct { 324 pattern, output, literal string 325 isLiteral bool 326 } 327 328 var metaTests = []MetaTest{ 329 {``, ``, ``, true}, 330 {`foo`, `foo`, `foo`, true}, 331 {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator 332 {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators 333 {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false}, 334 } 335 336 func TestQuoteMeta(t *testing.T) { 337 for _, tc := range metaTests { 338 // Verify that QuoteMeta returns the expected string. 339 quoted := QuoteMeta(tc.pattern) 340 if quoted != tc.output { 341 t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`", 342 tc.pattern, quoted, tc.output) 343 continue 344 } 345 346 // Verify that the quoted string is in fact treated as expected 347 // by Compile -- i.e. that it matches the original, unquoted string. 348 if tc.pattern != "" { 349 re, err := Compile(quoted) 350 if err != nil { 351 t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err) 352 continue 353 } 354 src := "abc" + tc.pattern + "def" 355 repl := "xyz" 356 replaced := re.ReplaceAllString(src, repl) 357 expected := "abcxyzdef" 358 if replaced != expected { 359 t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`", 360 tc.pattern, src, repl, replaced, expected) 361 } 362 } 363 } 364 } 365 366 func TestLiteralPrefix(t *testing.T) { 367 for _, tc := range metaTests { 368 // Literal method needs to scan the pattern. 369 re := MustCompile(tc.pattern) 370 str, complete := re.LiteralPrefix() 371 if complete != tc.isLiteral { 372 t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral) 373 } 374 if str != tc.literal { 375 t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal) 376 } 377 } 378 } 379 380 type subexpCase struct { 381 input string 382 num int 383 names []string 384 } 385 386 var subexpCases = []subexpCase{ 387 {``, 0, nil}, 388 {`.*`, 0, nil}, 389 {`abba`, 0, nil}, 390 {`ab(b)a`, 1, []string{"", ""}}, 391 {`ab(.*)a`, 1, []string{"", ""}}, 392 {`(.*)ab(.*)a`, 2, []string{"", "", ""}}, 393 {`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}}, 394 {`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}}, 395 {`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}}, 396 {`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}}, 397 {`(?P<foo>.*)(?P<bar>(a)b)(?P<foo>.*)a`, 4, []string{"", "foo", "bar", "", "foo"}}, 398 } 399 400 func TestSubexp(t *testing.T) { 401 for _, c := range subexpCases { 402 re := MustCompile(c.input) 403 n := re.NumSubexp() 404 if n != c.num { 405 t.Errorf("%q: NumSubexp = %d, want %d", c.input, n, c.num) 406 continue 407 } 408 names := re.SubexpNames() 409 if len(names) != 1+n { 410 t.Errorf("%q: len(SubexpNames) = %d, want %d", c.input, len(names), n) 411 continue 412 } 413 if c.names != nil { 414 for i := 0; i < 1+n; i++ { 415 if names[i] != c.names[i] { 416 t.Errorf("%q: SubexpNames[%d] = %q, want %q", c.input, i, names[i], c.names[i]) 417 } 418 } 419 } 420 } 421 } 422 423 var splitTests = []struct { 424 s string 425 r string 426 n int 427 out []string 428 }{ 429 {"foo:and:bar", ":", -1, []string{"foo", "and", "bar"}}, 430 {"foo:and:bar", ":", 1, []string{"foo:and:bar"}}, 431 {"foo:and:bar", ":", 2, []string{"foo", "and:bar"}}, 432 {"foo:and:bar", "foo", -1, []string{"", ":and:bar"}}, 433 {"foo:and:bar", "bar", -1, []string{"foo:and:", ""}}, 434 {"foo:and:bar", "baz", -1, []string{"foo:and:bar"}}, 435 {"baabaab", "a", -1, []string{"b", "", "b", "", "b"}}, 436 {"baabaab", "a*", -1, []string{"b", "b", "b"}}, 437 {"baabaab", "ba*", -1, []string{"", "", "", ""}}, 438 {"foobar", "f*b*", -1, []string{"", "o", "o", "a", "r"}}, 439 {"foobar", "f+.*b+", -1, []string{"", "ar"}}, 440 {"foobooboar", "o{2}", -1, []string{"f", "b", "boar"}}, 441 {"a,b,c,d,e,f", ",", 3, []string{"a", "b", "c,d,e,f"}}, 442 {"a,b,c,d,e,f", ",", 0, nil}, 443 {",", ",", -1, []string{"", ""}}, 444 {",,,", ",", -1, []string{"", "", "", ""}}, 445 {"", ",", -1, []string{""}}, 446 {"", ".*", -1, []string{""}}, 447 {"", ".+", -1, []string{""}}, 448 {"", "", -1, []string{}}, 449 {"foobar", "", -1, []string{"f", "o", "o", "b", "a", "r"}}, 450 {"abaabaccadaaae", "a*", 5, []string{"", "b", "b", "c", "cadaaae"}}, 451 {":x:y:z:", ":", -1, []string{"", "x", "y", "z", ""}}, 452 } 453 454 func TestSplit(t *testing.T) { 455 for i, test := range splitTests { 456 re, err := Compile(test.r) 457 if err != nil { 458 t.Errorf("#%d: %q: compile error: %s", i, test.r, err.Error()) 459 continue 460 } 461 462 split := re.Split(test.s, test.n) 463 if !reflect.DeepEqual(split, test.out) { 464 t.Errorf("#%d: %q: got %q; want %q", i, test.r, split, test.out) 465 } 466 467 if QuoteMeta(test.r) == test.r { 468 strsplit := strings.SplitN(test.s, test.r, test.n) 469 if !reflect.DeepEqual(split, strsplit) { 470 t.Errorf("#%d: Split(%q, %q, %d): regexp vs strings mismatch\nregexp=%q\nstrings=%q", i, test.s, test.r, test.n, split, strsplit) 471 } 472 } 473 } 474 } 475 476 func BenchmarkLiteral(b *testing.B) { 477 x := strings.Repeat("x", 50) + "y" 478 b.StopTimer() 479 re := MustCompile("y") 480 b.StartTimer() 481 for i := 0; i < b.N; i++ { 482 if !re.MatchString(x) { 483 b.Fatalf("no match!") 484 } 485 } 486 } 487 488 func BenchmarkNotLiteral(b *testing.B) { 489 x := strings.Repeat("x", 50) + "y" 490 b.StopTimer() 491 re := MustCompile(".y") 492 b.StartTimer() 493 for i := 0; i < b.N; i++ { 494 if !re.MatchString(x) { 495 b.Fatalf("no match!") 496 } 497 } 498 } 499 500 func BenchmarkMatchClass(b *testing.B) { 501 b.StopTimer() 502 x := strings.Repeat("xxxx", 20) + "w" 503 re := MustCompile("[abcdw]") 504 b.StartTimer() 505 for i := 0; i < b.N; i++ { 506 if !re.MatchString(x) { 507 b.Fatalf("no match!") 508 } 509 } 510 } 511 512 func BenchmarkMatchClass_InRange(b *testing.B) { 513 b.StopTimer() 514 // 'b' is between 'a' and 'c', so the charclass 515 // range checking is no help here. 516 x := strings.Repeat("bbbb", 20) + "c" 517 re := MustCompile("[ac]") 518 b.StartTimer() 519 for i := 0; i < b.N; i++ { 520 if !re.MatchString(x) { 521 b.Fatalf("no match!") 522 } 523 } 524 } 525 526 func BenchmarkReplaceAll(b *testing.B) { 527 x := "abcdefghijklmnopqrstuvwxyz" 528 b.StopTimer() 529 re := MustCompile("[cjrw]") 530 b.StartTimer() 531 for i := 0; i < b.N; i++ { 532 re.ReplaceAllString(x, "") 533 } 534 } 535 536 func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) { 537 b.StopTimer() 538 x := []byte("abcdefghijklmnopqrstuvwxyz") 539 re := MustCompile("^zbc(d|e)") 540 b.StartTimer() 541 for i := 0; i < b.N; i++ { 542 re.Match(x) 543 } 544 } 545 546 func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) { 547 b.StopTimer() 548 x := []byte("abcdefghijklmnopqrstuvwxyz") 549 for i := 0; i < 15; i++ { 550 x = append(x, x...) 551 } 552 re := MustCompile("^zbc(d|e)") 553 b.StartTimer() 554 for i := 0; i < b.N; i++ { 555 re.Match(x) 556 } 557 } 558 559 func BenchmarkAnchoredShortMatch(b *testing.B) { 560 b.StopTimer() 561 x := []byte("abcdefghijklmnopqrstuvwxyz") 562 re := MustCompile("^.bc(d|e)") 563 b.StartTimer() 564 for i := 0; i < b.N; i++ { 565 re.Match(x) 566 } 567 } 568 569 func BenchmarkAnchoredLongMatch(b *testing.B) { 570 b.StopTimer() 571 x := []byte("abcdefghijklmnopqrstuvwxyz") 572 for i := 0; i < 15; i++ { 573 x = append(x, x...) 574 } 575 re := MustCompile("^.bc(d|e)") 576 b.StartTimer() 577 for i := 0; i < b.N; i++ { 578 re.Match(x) 579 } 580 }