camel.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. package casing
  2. // Camel returns the CamelCased name.
  3. //
  4. // This was moved from the now deprecated github.com/golang/protobuf/protoc-gen-go/generator package
  5. //
  6. // If there is an interior underscore followed by a lower case letter,
  7. // drop the underscore and convert the letter to upper case.
  8. // There is a remote possibility of this rewrite causing a name collision,
  9. // but it's so remote we're prepared to pretend it's nonexistent - since the
  10. // C++ generator lowercases names, it's extremely unlikely to have two fields
  11. // with different capitalizations.
  12. // In short, _my_field_name_2 becomes XMyFieldName_2.
  13. func Camel(s string) string {
  14. if s == "" {
  15. return ""
  16. }
  17. t := make([]byte, 0, 32)
  18. i := 0
  19. if s[0] == '_' {
  20. // Need a capital letter; drop the '_'.
  21. t = append(t, 'X')
  22. i++
  23. }
  24. // Invariant: if the next letter is lower case, it must be converted
  25. // to upper case.
  26. // That is, we process a word at a time, where words are marked by _ or
  27. // upper case letter. Digits are treated as words.
  28. for ; i < len(s); i++ {
  29. c := s[i]
  30. if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
  31. continue // Skip the underscore in s.
  32. }
  33. if isASCIIDigit(c) {
  34. t = append(t, c)
  35. continue
  36. }
  37. // Assume we have a letter now - if not, it's a bogus identifier.
  38. // The next word is a sequence of characters that must start upper case.
  39. if isASCIILower(c) {
  40. c ^= ' ' // Make it a capital letter.
  41. }
  42. t = append(t, c) // Guaranteed not lower case.
  43. // Accept lower case sequence that follows.
  44. for i+1 < len(s) && isASCIILower(s[i+1]) {
  45. i++
  46. t = append(t, s[i])
  47. }
  48. }
  49. return string(t)
  50. }
  51. // And now lots of helper functions.
  52. // Is c an ASCII lower-case letter?
  53. func isASCIILower(c byte) bool {
  54. return 'a' <= c && c <= 'z'
  55. }
  56. // Is c an ASCII digit?
  57. func isASCIIDigit(c byte) bool {
  58. return '0' <= c && c <= '9'
  59. }