gitee.com/gricks/utils@v1.0.8/casee.go (about)

     1  package utils
     2  
     3  import (
     4  	"strings"
     5  	"unicode"
     6  	"unicode/utf8"
     7  )
     8  
     9  // Splitting rules
    10  //
    11  //  1) If string is not valid UTF-8, return it without splitting as
    12  //     single item array.
    13  //  2) Assign all unicode characters into one of 4 sets: lower case
    14  //     letters, upper case letters, numbers, and all other characters.
    15  //  3) Iterate through characters of string, introducing splits
    16  //     between adjacent characters that belong to different sets.
    17  //  4) Iterate through array of split strings, and if a given string
    18  //     is upper case:
    19  //       if subsequent string is lower case:
    20  //         move last character of upper case string to beginning of
    21  //         lower case string
    22  func CamelcaseSplit(src string) (entries []string) {
    23  	// don't split invalid utf8
    24  	if !utf8.ValidString(src) {
    25  		return []string{src}
    26  	}
    27  	entries = []string{}
    28  	var runes [][]rune
    29  	lastClass := 0
    30  	class := 0
    31  	// split into fields based on class of unicode character
    32  	for _, r := range src {
    33  		switch true {
    34  		case unicode.IsLower(r):
    35  			class = 1
    36  		case unicode.IsUpper(r):
    37  			class = 2
    38  		case unicode.IsDigit(r):
    39  			class = 3
    40  		default:
    41  			class = 4
    42  		}
    43  		if class == lastClass {
    44  			runes[len(runes)-1] = append(runes[len(runes)-1], r)
    45  		} else {
    46  			runes = append(runes, []rune{r})
    47  		}
    48  		lastClass = class
    49  	}
    50  	// handle upper case -> lower case sequences, e.g.
    51  	// "PDFL", "oader" -> "PDF", "Loader"
    52  	for i := 0; i < len(runes)-1; i++ {
    53  		if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
    54  			runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
    55  			runes[i] = runes[i][:len(runes[i])-1]
    56  		}
    57  	}
    58  	// construct []string from results
    59  	for _, s := range runes {
    60  		if len(s) > 0 {
    61  			entries = append(entries, string(s))
    62  		}
    63  	}
    64  	return
    65  }
    66  
    67  type SplitCase int
    68  
    69  const (
    70  	NoneCase  SplitCase = 0
    71  	LowerCase SplitCase = 1
    72  	UpperCase SplitCase = 2
    73  	TitleCase SplitCase = 3
    74  )
    75  
    76  // Split a string to fields
    77  func Split2fields(s string, c SplitCase) []string {
    78  	fields := make([]string, 0, len([]rune(s))/3)
    79  	for _, sf := range strings.Fields(s) {
    80  		for _, su := range strings.Split(sf, "_") {
    81  			for _, sh := range strings.Split(su, "-") {
    82  				for _, sc := range CamelcaseSplit(sh) {
    83  					switch c {
    84  					case LowerCase:
    85  						sc = strings.ToLower(sc)
    86  					case UpperCase:
    87  						sc = strings.ToUpper(sc)
    88  					case TitleCase:
    89  						sc = strings.ToTitle(sc)
    90  					default:
    91  					}
    92  					fields = append(fields, strings.ToLower(sc))
    93  				}
    94  			}
    95  		}
    96  	}
    97  	return fields
    98  }
    99  
   100  // Convert argument to snake_case style string.
   101  func ToSnakeCase(s string) string {
   102  	if len(s) == 0 {
   103  		return s
   104  	}
   105  	return strings.Join(Split2fields(s, LowerCase), "_")
   106  }
   107  
   108  // Convert argument to chain-case style string.
   109  func ToChainCase(s string) string {
   110  	if len(s) == 0 {
   111  		return s
   112  	}
   113  	return strings.Join(Split2fields(s, LowerCase), "-")
   114  }
   115  
   116  // Convert argument to PascalCase style string
   117  func ToPascalCase(s string) string {
   118  	if len(s) == 0 {
   119  		return s
   120  	}
   121  	return strings.Join(Split2fields(s, TitleCase), "")
   122  }
   123  
   124  // Convert argument to camelCase style string
   125  func ToCamelCase(s string) string {
   126  	if len(s) == 0 {
   127  		return s
   128  	}
   129  	fields := Split2fields(s, TitleCase)
   130  	if len(fields) > 0 {
   131  		fields[0] = strings.ToLower(fields[0])
   132  	}
   133  	return strings.Join(fields, "")
   134  }