@@ -12,14 +12,21 @@ func ToSnake(s string) string { | |||||
n := "" | n := "" | ||||
for i, v := range s { | for i, v := range s { | ||||
// treat acronyms as words, eg for JSONData -> JSON is a whole word | // treat acronyms as words, eg for JSONData -> JSON is a whole word | ||||
preIsCapital := false | |||||
if i > 0 { | |||||
w := s[i-1] | |||||
preIsCapital = w >= 'A' && w <= 'Z' | |||||
nextCaseIsChanged := false | |||||
if i+1 < len(s) { | |||||
next := s[i+1] | |||||
if (v >= 'A' && v <= 'Z' && next >= 'a' && next <= 'z') || (v >= 'a' && v <= 'z' && next >= 'A' && next <= 'Z') { | |||||
nextCaseIsChanged = true | |||||
} | |||||
} | } | ||||
if i > 0 && v >= 'A' && v <= 'Z' && n[len(n)-1] != '_' && !preIsCapital { | |||||
// add underscore if next letter is a capital | |||||
n += "_" + string(v) | |||||
if i > 0 && n[len(n)-1] != '_' && nextCaseIsChanged { | |||||
// add underscore if next letter case type is changed | |||||
if v >= 'A' && v <= 'Z' { | |||||
n += "_" + string(v) | |||||
} else if v >= 'a' && v <= 'z' { | |||||
n += string(v) + "_" | |||||
} | |||||
} else if v == ' ' { | } else if v == ' ' { | ||||
// replace spaces with underscores | // replace spaces with underscores | ||||
n += "_" | n += "_" | ||||
@@ -21,6 +21,8 @@ func TestToSnake(t *testing.T) { | |||||
[]string{"AnyKind of_string", "any_kind_of_string"}, | []string{"AnyKind of_string", "any_kind_of_string"}, | ||||
[]string{"numbers2and55with000", "numbers_2_and_55_with_000"}, | []string{"numbers2and55with000", "numbers_2_and_55_with_000"}, | ||||
[]string{"JSONData", "json_data"}, | []string{"JSONData", "json_data"}, | ||||
[]string{"userID", "user_id"}, | |||||
[]string{"AAAbbb", "aa_abbb"}, | |||||
} | } | ||||
for _, i := range cases { | for _, i := range cases { | ||||
in := i[0] | in := i[0] | ||||