|
| 1 | +package anycase |
| 2 | + |
| 3 | +import ( |
| 4 | + "strings" |
| 5 | +) |
| 6 | + |
| 7 | +// ToSnake converts a string to snake_case |
| 8 | +func ToSnake(s string) string { |
| 9 | + |
| 10 | + return ToDelimited(s, '_') |
| 11 | +} |
| 12 | + |
| 13 | +// ToSnakeAndIgnore converts to snake_case and ignores the following characters arg |
| 14 | +func ToSnakeAndIgnore(s string, ignore uint8) string { |
| 15 | + |
| 16 | + return ToDelimitedUppercase(s, '_', ignore, false) |
| 17 | +} |
| 18 | + |
| 19 | +// ToSnakeUppercase converts a string to UPPERCASE_SNAKE_CASE |
| 20 | +func ToSnakeUppercase(s string) string { |
| 21 | + return ToDelimitedUppercase(s, '_', 0, true) |
| 22 | +} |
| 23 | + |
| 24 | +// ToKebab converts a string to kebab-case |
| 25 | +func ToKebab(s string) string { |
| 26 | + return ToDelimited(s, '-') |
| 27 | +} |
| 28 | + |
| 29 | +// ToKebabUppercase converts a string to UPPERCASE-KEBAB-CASE |
| 30 | +func ToKebabUppercase(s string) string { |
| 31 | + return ToDelimitedUppercase(s, '-', 0, true) |
| 32 | +} |
| 33 | + |
| 34 | +// ToDelimited converts a string to delimited.snake.case |
| 35 | +// (in this case `delimiter = '.'`) |
| 36 | +func ToDelimited(s string, delimiter uint8) string { |
| 37 | + return ToDelimitedUppercase(s, delimiter, 0, false) |
| 38 | +} |
| 39 | + |
| 40 | +// ToDelimitedUppercase converts a string to UPPERCASE.DELIMITED.SNAKE.CASE |
| 41 | +// (in this case `delimiter = '.'; uppercase = true`) |
| 42 | +// or delimited.snake.case |
| 43 | +// (in this case `delimiter = '.'; uppercase = false`) |
| 44 | +func ToDelimitedUppercase(s string, delimiter uint8, ignore uint8, uppercase bool) string { |
| 45 | + s = addWordBoundariesToNumbers(s) |
| 46 | + s = strings.Trim(s, " ") |
| 47 | + n := "" |
| 48 | + for i, v := range s { |
| 49 | + // treat acronyms as words, eg for JSONData -> JSON is a whole word |
| 50 | + nextCaseIsChanged := false |
| 51 | + if i+1 < len(s) { |
| 52 | + next := s[i+1] |
| 53 | + vIsCap := v >= 'A' && v <= 'Z' |
| 54 | + vIsLow := v >= 'a' && v <= 'z' |
| 55 | + nextIsCap := next >= 'A' && next <= 'Z' |
| 56 | + nextIsLow := next >= 'a' && next <= 'z' |
| 57 | + if (vIsCap && nextIsLow) || (vIsLow && nextIsCap) { |
| 58 | + nextCaseIsChanged = true |
| 59 | + } |
| 60 | + if ignore > 0 && i-1 >= 0 && s[i-1] == ignore && nextCaseIsChanged { |
| 61 | + nextCaseIsChanged = false |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + if i > 0 && n[len(n)-1] != delimiter && nextCaseIsChanged { |
| 66 | + // add underscore if next letter case type is changed |
| 67 | + if v >= 'A' && v <= 'Z' { |
| 68 | + n += string(delimiter) + string(v) |
| 69 | + } else if v >= 'a' && v <= 'z' { |
| 70 | + n += string(v) + string(delimiter) |
| 71 | + } |
| 72 | + } else if v == ' ' || v == '_' || v == '-' { |
| 73 | + // replace spaces/underscores with delimiters |
| 74 | + if uint8(v) == ignore { |
| 75 | + n += string(v) |
| 76 | + } else { |
| 77 | + n += string(delimiter) |
| 78 | + } |
| 79 | + } else { |
| 80 | + n = n + string(v) |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + if uppercase { |
| 85 | + n = strings.ToUpper(n) |
| 86 | + } else { |
| 87 | + n = strings.ToLower(n) |
| 88 | + } |
| 89 | + return n |
| 90 | +} |
0 commit comments