|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- /*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Ian Coleman
- * Copyright (c) 2018 Ma_124, <github.com/Ma124>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, Subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or Substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- package strcase
-
- import (
- "strings"
- )
-
- // ToSnake converts a string to snake_case
- func ToSnake(s string) string {
- return ToDelimited(s, '_')
- }
-
- func ToSnakeWithIgnore(s string, ignore uint8) string {
- return ToScreamingDelimited(s, '_', ignore, false)
- }
-
- // ToScreamingSnake converts a string to SCREAMING_SNAKE_CASE
- func ToScreamingSnake(s string) string {
- return ToScreamingDelimited(s, '_', 0, true)
- }
-
- // ToKebab converts a string to kebab-case
- func ToKebab(s string) string {
- return ToDelimited(s, '-')
- }
-
- // ToScreamingKebab converts a string to SCREAMING-KEBAB-CASE
- func ToScreamingKebab(s string) string {
- return ToScreamingDelimited(s, '-', 0, true)
- }
-
- // ToDelimited converts a string to delimited.snake.case
- // (in this case `delimiter = '.'`)
- func ToDelimited(s string, delimiter uint8) string {
- return ToScreamingDelimited(s, delimiter, 0, false)
- }
-
- // ToScreamingDelimited converts a string to SCREAMING.DELIMITED.SNAKE.CASE
- // (in this case `delimiter = '.'; screaming = true`)
- // or delimited.snake.case
- // (in this case `delimiter = '.'; screaming = false`)
- func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming bool) string {
- n := strings.Builder{}
- n.Grow(len(s) + 2) // nominal 2 bytes of extra space for inserted delimiters
- start := true
- spaces := 0
- for i, v := range []byte(s) {
- if v == ' ' {
- spaces++
- continue
- } else if start {
- start = false
- spaces = 0
- } else {
- for ; spaces > 0; spaces-- {
- if ignore == ' ' {
- n.WriteByte(' ')
- } else {
- n.WriteByte(delimiter)
- }
- }
- }
-
- vIsCap := v >= 'A' && v <= 'Z'
- vIsLow := v >= 'a' && v <= 'z'
- if vIsLow && screaming {
- v += 'A'
- v -= 'a'
- } else if vIsCap && !screaming {
- v += 'a'
- v -= 'A'
- }
-
- // treat acronyms as words, eg for JSONData -> JSON is a whole word
- if i+1 < len(s) {
- next := s[i+1]
- vIsNum := v >= '0' && v <= '9'
- nextIsCap := next >= 'A' && next <= 'Z'
- nextIsLow := next >= 'a' && next <= 'z'
- nextIsNum := next >= '0' && next <= '9'
- // add underscore if next letter case type is changed
- if (vIsCap && (nextIsLow || nextIsNum)) || (vIsLow && (nextIsCap || nextIsNum)) || (vIsNum && (nextIsCap || nextIsLow)) {
- if prevIgnore := ignore > 0 && i > 0 && s[i-1] == ignore; !prevIgnore {
- if vIsCap && nextIsLow {
- if prevIsCap := i > 0 && s[i-1] >= 'A' && s[i-1] <= 'Z'; prevIsCap {
- n.WriteByte(delimiter)
- }
- }
- n.WriteByte(v)
- if vIsLow || vIsNum || nextIsNum {
- n.WriteByte(delimiter)
- }
- continue
- }
- }
- }
-
- if (v == ' ' || v == '_' || v == '-') && uint8(v) != ignore {
- // replace space/underscore/hyphen with delimiter
- n.WriteByte(delimiter)
- } else {
- n.WriteByte(v)
- }
- }
-
- return n.String()
- }
|