package utini import ( "strings" "unicode" ) type characterCasing int const ( undefinedCase characterCasing = iota lowerCase upperCase ) func camelCaseToSnakeCase(name string) string { segments := strings.Split(name, ".") if len(segments) > 1 { for i, segment := range segments { segments[i] = camelCaseToSnakeCase(segment) } return strings.Join(segments, ".") } var words []string runes := []rune(name) if len(runes) == 0 { return "" } n := len(runes) end := n casing := undefinedCase for i := range runes { j := n - i - 1 r := runes[j] if unicode.IsLower(r) { if casing == upperCase { words = append(words, strings.ToLower(string(runes[j+1:end]))) end = j + 1 casing = undefinedCase } else { casing = lowerCase } } else if r == '_' { if end-j > 1 { words = append(words, strings.ToLower(string(runes[j+1:end]))) end = j } casing = undefinedCase } else if unicode.IsDigit(r) { // acts like either upper or lowercase depending on which character was following. } else { if casing == lowerCase { words = append(words, strings.ToLower(string(runes[j:end]))) end = j casing = undefinedCase } else { casing = upperCase } } } if end > 0 { words = append(words, strings.ToLower(string(runes[:end]))) } // reverse order of words last := len(words) - 1 for i := 0; i < len(words)/2; i++ { words[i], words[last-i] = words[last-i], words[i] } return strings.Join(words, "_") } func snakeCaseToCamelCase(name string) string { words := strings.Split(name, `_`) for i, word := range words { runes := []rune(word) first := strings.IndexFunc(word, unicode.IsLetter) if first > -1 { runes[first] = unicode.ToUpper(runes[first]) } words[i] = string(runes) } return strings.Join(words, ``) }