github.com/mailru/activerecord@v1.12.2/pkg/iproto/util/text/text.go (about) 1 // Package text contains utilities for text manipulation. 2 package text 3 4 import ( 5 "bytes" 6 "regexp" 7 "strings" 8 "unicode" 9 ) 10 11 // Split2 splits a string into 2 parts: before and after sep. Split2 is faster than 12 // equivalent strings.SplitN and does no allocations. Looking for the first occurrence of a delimiter. 13 func Split2(s string, sep byte) (left, right string) { 14 for i := 0; i < len(s); i++ { 15 if s[i] == sep { 16 return s[:i], s[i+1:] 17 } 18 } 19 20 return s, "" 21 } 22 23 // Split2Reversed splits a string into 2 parts: before and after sep. Split2Reversed is faster than 24 // equivalent strings.SplitN and does no allocations. Looking for the last occurrence of a delimiter. 25 func Split2Reversed(s string, sep byte) (left, right string) { 26 for i := len(s) - 1; i >= 0; i-- { 27 if s[i] == sep { 28 return s[:i], s[i+1:] 29 } 30 } 31 32 return s, "" 33 } 34 35 // ToSnakeCase converts given name to "snake_text_format". 36 func ToSnakeCase(name string) string { 37 multipleUpper := false 38 39 var ( 40 ret bytes.Buffer 41 lastUpper rune 42 beforeUpper rune 43 ) 44 45 for _, c := range name { 46 // Non-lowercase character after uppercase is considered to be uppercase too. 47 isUpper := (unicode.IsUpper(c) || (lastUpper != 0 && !unicode.IsLower(c))) 48 49 // Output a delimiter if last character was either the first uppercase character 50 // in a row, or the last one in a row (e.g. 'S' in "HTTPServer"). 51 // Do not output a delimiter at the beginning of the name. 52 if lastUpper != 0 { 53 firstInRow := !multipleUpper 54 lastInRow := !isUpper 55 56 if ret.Len() > 0 && (firstInRow || lastInRow) && beforeUpper != '_' { 57 ret.WriteByte('_') 58 } 59 60 ret.WriteRune(unicode.ToLower(lastUpper)) 61 } 62 63 // Buffer uppercase char, do not output it yet as a delimiter may be required if the 64 // next character is lowercase. 65 if isUpper { 66 multipleUpper = (lastUpper != 0) 67 lastUpper = c 68 69 continue 70 } 71 72 ret.WriteRune(c) 73 74 lastUpper = 0 75 beforeUpper = c 76 multipleUpper = false 77 } 78 79 if lastUpper != 0 { 80 ret.WriteRune(unicode.ToLower(lastUpper)) 81 } 82 83 return ret.String() 84 } 85 86 var snakePattern = regexp.MustCompile("(^[A-Za-z])|_([A-Za-z])") 87 88 func SnakeToCamelCase(str string) string { 89 return snakePattern.ReplaceAllStringFunc(str, func(s string) string { 90 return strings.ToUpper(strings.Replace(s, "_", "", -1)) 91 }) 92 }