Browse Source

Performance optimizations

tags/v0.1.0^2
Nathan Baulch 3 years ago
parent
commit
820267b5d9
3 changed files with 67 additions and 39 deletions
  1. +2
    -2
      acronyms.go
  2. +28
    -21
      camel.go
  3. +37
    -16
      snake.go

+ 2
- 2
acronyms.go View File

@@ -1,5 +1,5 @@
package strcase

var uppercaseAcronym = map[string]bool{
"ID": true,
var uppercaseAcronym = map[string]string{
"ID": "id",
}

+ 28
- 21
camel.go View File

@@ -31,40 +31,47 @@ import (

// Converts a string to CamelCase
func toCamelInitCase(s string, initCase bool) string {
if s == "" {
return s
}
if a, ok := uppercaseAcronym[s]; ok {
s = a
}

s = addWordBoundariesToNumbers(s)
n := ""
n := strings.Builder{}
n.Grow(len(s))
capNext := initCase
for _, v := range s {
if capNext && v >= 'a' && v <= 'z' {
v = int32(strings.ToUpper(string(v))[0])
for i, v := range []byte(s) {
vIsCap := v >= 'A' && v <= 'Z'
vIsLow := v >= 'a' && v <= 'z'
if capNext {
if vIsLow {
v += 'A'
v -= 'a'
}
} else if i == 0 {
if vIsCap {
v += 'a'
v -= 'A'
}
}
if (v >= 'A' && v <= 'Z') ||
(v >= 'a' && v <= 'z') ||
(v >= '0' && v <= '9') {
n += string(v)
if vIsCap || vIsLow || (v >= '0' && v <= '9') {
n.WriteByte(v)
capNext = false
} else {
capNext = v == '_' || v == ' ' || v == '-' || v == '.'
}
capNext = v == '_' || v == ' ' || v == '-' || v == '.'
}
return n
return n.String()
}

// ToCamel converts a string to CamelCase
func ToCamel(s string) string {
if uppercaseAcronym[s] {
s = strings.ToLower(s)
}
return toCamelInitCase(s, true)
}

// ToLowerCamel converts a string to lowerCamelCase
func ToLowerCamel(s string) string {
if s == "" {
return s
}
if uppercaseAcronym[s] {
s = strings.ToLower(s)
} else if r := s[0]; r >= 'A' && r <= 'Z' {
s = strings.ToLower(string(r)) + s[1:]
}
return toCamelInitCase(s, false)
}

+ 37
- 16
snake.go View File

@@ -65,14 +65,40 @@ func ToDelimited(s string, delimiter uint8) string {
// (in this case `delimiter = '.'; screaming = false`)
func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming bool) string {
s = addWordBoundariesToNumbers(s)
s = strings.Trim(s, " ")
n := ""
for i, v := range s {
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]
vIsCap := v >= 'A' && v <= 'Z'
vIsLow := v >= 'a' && v <= 'z'
nextIsCap := next >= 'A' && next <= 'Z'
nextIsLow := next >= 'a' && next <= 'z'
// add underscore if next letter case type is changed
@@ -80,12 +106,12 @@ func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming boo
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 += string(delimiter)
n.WriteByte(delimiter)
}
}
n += string(v)
n.WriteByte(v)
if vIsLow {
n += string(delimiter)
n.WriteByte(delimiter)
}
continue
}
@@ -94,16 +120,11 @@ func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming boo

if (v == ' ' || v == '_' || v == '-') && uint8(v) != ignore {
// replace space/underscore/hyphen with delimiter
n += string(delimiter)
n.WriteByte(delimiter)
} else {
n += string(v)
n.WriteByte(v)
}
}

if screaming {
n = strings.ToUpper(n)
} else {
n = strings.ToLower(n)
}
return n
return n.String()
}

Loading…
Cancel
Save