You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.7 KiB
98 lines
2.7 KiB
6 years ago
|
|
||
|
package utils
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
// Is c an ASCII lower-case letter?
|
||
|
func isASCIILower(c byte) bool {
|
||
|
return 'a' <= c && c <= 'z'
|
||
|
}
|
||
|
|
||
|
// Is c an ASCII digit?
|
||
|
func isASCIIDigit(c byte) bool {
|
||
|
return '0' <= c && c <= '9'
|
||
|
}
|
||
|
|
||
|
// CamelCase converts a string from snake_case to CamelCased.
|
||
|
//
|
||
|
// If there is an interior underscore followed by a lower case letter, drop the
|
||
|
// underscore and convert the letter to upper case. There is a remote
|
||
|
// possibility of this rewrite causing a name collision, but it's so remote
|
||
|
// we're prepared to pretend it's nonexistent - since the C++ generator
|
||
|
// lowercases names, it's extremely unlikely to have two fields with different
|
||
|
// capitalizations. In short, _my_field_name_2 becomes XMyFieldName_2.
|
||
|
func CamelCase(s string) string {
|
||
|
if s == "" {
|
||
|
return ""
|
||
|
}
|
||
|
t := make([]byte, 0, 32)
|
||
|
i := 0
|
||
|
if s[0] == '_' {
|
||
|
// Need a capital letter; drop the '_'.
|
||
|
t = append(t, 'X')
|
||
|
i++
|
||
|
}
|
||
|
// Invariant: if the next letter is lower case, it must be converted
|
||
|
// to upper case.
|
||
|
//
|
||
|
// That is, we process a word at a time, where words are marked by _ or upper
|
||
|
// case letter. Digits are treated as words.
|
||
|
for ; i < len(s); i++ {
|
||
|
c := s[i]
|
||
|
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
|
||
|
continue // Skip the underscore in s.
|
||
|
}
|
||
|
if isASCIIDigit(c) {
|
||
|
t = append(t, c)
|
||
|
continue
|
||
|
}
|
||
|
// Assume we have a letter now - if not, it's a bogus identifier. The next
|
||
|
// word is a sequence of characters that must start upper case.
|
||
|
if isASCIILower(c) {
|
||
|
c ^= ' ' // Make it a capital letter.
|
||
|
}
|
||
|
t = append(t, c) // Guaranteed not lower case.
|
||
|
// Accept lower case sequence that follows.
|
||
|
for i+1 < len(s) && isASCIILower(s[i+1]) {
|
||
|
i++
|
||
|
t = append(t, s[i])
|
||
|
}
|
||
|
}
|
||
|
return string(t)
|
||
|
}
|
||
|
|
||
|
// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
|
||
|
// be joined with "_" and then camelcased.
|
||
|
func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
|
||
|
|
||
|
// BaseName the last path element of a slash-delimited name, with the last
|
||
|
// dotted suffix removed.
|
||
|
func BaseName(name string) string {
|
||
|
// First, find the last element
|
||
|
if i := strings.LastIndex(name, "/"); i >= 0 {
|
||
|
name = name[i+1:]
|
||
|
}
|
||
|
// Now drop the suffix
|
||
|
if i := strings.LastIndex(name, "."); i >= 0 {
|
||
|
name = name[0:i]
|
||
|
}
|
||
|
return name
|
||
|
}
|
||
|
|
||
|
// AlphaDigitize replaces non-letter, non-digit, non-underscore characters with
|
||
|
// underscore.
|
||
|
func AlphaDigitize(r rune) rune {
|
||
|
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
|
||
|
return r
|
||
|
}
|
||
|
return '_'
|
||
|
}
|
||
|
|
||
|
// CleanIdentifier makes sure s is a valid 'identifier' string: it contains only
|
||
|
// letters, numbers, and underscore.
|
||
|
func CleanIdentifier(s string) string {
|
||
|
return strings.Map(AlphaDigitize, s)
|
||
|
}
|