diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go index 31843d41f1..beb46e7099 100644 --- a/src/regexp/all_test.go +++ b/src/regexp/all_test.go @@ -818,3 +818,23 @@ func BenchmarkMatchParallelCopied(b *testing.B) { } }) } + +var sink string + +func BenchmarkQuoteMetaAll(b *testing.B) { + s := string(specialBytes) + b.SetBytes(int64(len(s))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink = QuoteMeta(s) + } +} + +func BenchmarkQuoteMetaNone(b *testing.B) { + s := "abcdefghijklmnopqrstuvwxyz" + b.SetBytes(int64(len(s))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink = QuoteMeta(s) + } +} diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index 87a3e88d9a..01093d4bd0 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -600,11 +600,22 @@ func special(b byte) bool { // inside the argument text; the returned string is a regular expression matching // the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`. func QuoteMeta(s string) string { - b := make([]byte, 2*len(s)) - // A byte loop is correct because all metacharacters are ASCII. - j := 0 - for i := 0; i < len(s); i++ { + var i int + for i = 0; i < len(s); i++ { + if special(s[i]) { + break + } + } + // No meta characters found, so return original string. + if i >= len(s) { + return s + } + + b := make([]byte, 2*len(s)-i) + copy(b, s[:i]) + j := i + for ; i < len(s); i++ { if special(s[i]) { b[j] = '\\' j++ @@ -612,7 +623,7 @@ func QuoteMeta(s string) string { b[j] = s[i] j++ } - return string(b[0:j]) + return string(b[:j]) } // The number of capture values in the program may correspond