どうやるのがベストなのかよく知らないので色々書いてみた。
package main
import (
"bytes"
"regexp"
"strings"
"testing"
"unicode"
)
func BenchmarkSplitJoin(b *testing.B) {
b.StopTimer()
s := "hoge_foo_bar"
b.StartTimer()
for i := 0; i < b.N; i++ {
ss := strings.Split(s, "_")
var buf bytes.Buffer
for _, v := range ss {
buf.WriteString(strings.Title(v))
buf.String()
}
}
}
func BenchmarkReplace(b *testing.B) {
b.StopTimer()
s := "hoge_foo_bar"
b.StartTimer()
for i := 0; i < b.N; i++ {
strings.Replace(strings.Title(strings.Replace(s, "_", " ", -1)), " ", "", -1)
}
}
func BenchmarkRegexp(b *testing.B) {
b.StopTimer()
s := "hoge_foo_bar"
r := regexp.MustCompile(`_([a-z])`)
fn := func(m string) string {
return strings.ToUpper(string(m[1]))
}
b.StartTimer()
for i := 0; i < b.N; i++ {
strings.Title(r.ReplaceAllStringFunc(s, fn))
}
}
func BenchmarkForLoop(b *testing.B) {
b.StopTimer()
s := "hoge_foo_bar"
b.StartTimer()
for i := 0; i < b.N; i++ {
buf := make([]rune, 0, len(s))
conv := false
for _, v := range s {
if v == '_' {
conv = true
continue
}
if conv {
buf = append(buf, unicode.ToUpper(v))
conv = false
continue
}
buf = append(buf, v)
}
buf[0] = unicode.ToUpper(buf[0])
_ = string(buf)
}
}
私の環境でのベンチ結果はこんな感じ。
% go test -bench .
testing: warning: no tests to run
PASS
BenchmarkSplitJoin 1000000 1553 ns/op
BenchmarkReplace 1000000 1220 ns/op
BenchmarkRegexp 1000000 2848 ns/op
BenchmarkForLoop 5000000 396 ns/op
ok _/home/naoina/work/test/bench 8.056s