Skip to content

Instantly share code, notes, and snippets.

@regeda
Last active December 12, 2018 10:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save regeda/969a067ff4ed6ffa8ed6 to your computer and use it in GitHub Desktop.
Save regeda/969a067ff4ed6ffa8ed6 to your computer and use it in GitHub Desktop.
Convert CamelCase to underscore in golang with UTF-8 support.
package main
import (
"testing"
"unicode"
"unicode/utf8"
"github.com/stretchr/testify/assert"
)
type buffer struct {
r []byte
runeBytes [utf8.UTFMax]byte
}
func (b *buffer) write(r rune) {
if r < utf8.RuneSelf {
b.r = append(b.r, byte(r))
return
}
n := utf8.EncodeRune(b.runeBytes[0:], r)
b.r = append(b.r, b.runeBytes[0:n]...)
}
func (b *buffer) indent() {
if len(b.r) > 0 {
b.r = append(b.r, '_')
}
}
func underscore(s string) string {
b := buffer{
r: make([]byte, 0, len(s)),
}
var m rune
var w bool
for _, ch := range s {
if unicode.IsUpper(ch) {
if m != 0 {
if !w {
b.indent()
w = true
}
b.write(m)
}
m = unicode.ToLower(ch)
} else {
if m != 0 {
b.indent()
b.write(m)
m = 0
w = false
}
b.write(ch)
}
}
if m != 0 {
if !w {
b.indent()
}
b.write(m)
}
return string(b.r)
}
func TestUnderscore(t *testing.T) {
assert.Equal(t, "i_love_golang_and_json_so_much", underscore("ILoveGolangAndJSONSoMuch"))
assert.Equal(t, "i_love_json", underscore("ILoveJSON"))
assert.Equal(t, "json", underscore("json"))
assert.Equal(t, "json", underscore("JSON"))
assert.Equal(t, "привет_мир", underscore("ПриветМир"))
}
// BenchmarkUnderscore-4 10000000 209 ns/op
func BenchmarkUnderscore(b *testing.B) {
for n := 0; n < b.N; n++ {
underscore("TestTable")
}
}
@Bartuz
Copy link

Bartuz commented Jun 19, 2017

You can also find camelCaseToUnderscore function in govalidator package.
https://github.com/asaskevich/govalidator/blob/master/utils.go#L107-L119

so you call it govalidator.CamelCaseToUnderscore(camelCasedVariableName). Remember to add "github.com/asaskevich/govalidator" to imports :)

@regeda
Copy link
Author

regeda commented Aug 13, 2017

@Bartuz thanks for the link but govalidator.CamelCaseToUnderscore(camelCasedVariableName) works incorrectly. Pls, test with the following fixture ILoveGolangAndJSONSoMuch. The expected result should be i_love_golang_and_json_so_much. But the function returns i_love_golang_and_j_s_o_n_so_much

@zxh
Copy link

zxh commented Mar 17, 2018

@regeda this is my solution for converting camelcase to underscore in golang.
https://gist.github.com/zxh/cee082053aa9674812e8cd4387088301
It can handle the case: ILoveGolangAndJSONSoMuch.
: )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment