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  }