github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zstring/string.go (about)

     1  // Package zstring provides String related operations
     2  package zstring
     3  
     4  import (
     5  	"bytes"
     6  	"fmt"
     7  	"regexp"
     8  	"strings"
     9  	"unicode"
    10  	"unicode/utf8"
    11  	"unsafe"
    12  )
    13  
    14  type (
    15  	// ru is a pseudorandom number generator
    16  	ru struct {
    17  		x uint32
    18  	}
    19  	PadType uint8
    20  )
    21  
    22  const (
    23  	// PadRight Right padding character
    24  	PadRight PadType = iota
    25  	// PadLeft Left padding character
    26  	PadLeft
    27  	// PadSides Two-sided padding characters,If the two sides are not equal, the right side takes precedence.
    28  	PadSides
    29  	letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    30  )
    31  
    32  // Pad String padding
    33  func Pad(raw string, length int, padStr string, padType PadType) string {
    34  	l := length - Len(raw)
    35  	if l <= 0 {
    36  		return raw
    37  	}
    38  	if padType == PadRight {
    39  		raw = fmt.Sprintf("%s%s", raw, strings.Repeat(padStr, l))
    40  	} else if padType == PadLeft {
    41  		raw = fmt.Sprintf("%s%s", strings.Repeat(padStr, l), raw)
    42  	} else {
    43  		left := 0
    44  		right := 0
    45  		if l > 1 {
    46  			left = l / 2
    47  			right = (l / 2) + (l % 2)
    48  		}
    49  
    50  		raw = fmt.Sprintf("%s%s%s", strings.Repeat(padStr, left), raw, strings.Repeat(padStr, right))
    51  	}
    52  	return raw
    53  }
    54  
    55  // Len string length (utf8)
    56  func Len(str string) int {
    57  	// strings.Count(str,"")-1
    58  	return utf8.RuneCountInString(str)
    59  }
    60  
    61  // Substr returns part of a string
    62  func Substr(str string, start int, length ...int) string {
    63  	var size, ll, n, nn int
    64  	if len(length) > 0 {
    65  		ll = length[0] + start
    66  	}
    67  	lb := ll == 0
    68  	if start < 0 {
    69  		start = Len(str) + start
    70  	}
    71  	for i := 0; i < len(str); i++ {
    72  		_, size = utf8.DecodeRuneInString(str[nn:])
    73  		if i < start {
    74  			n += size
    75  		} else if lb {
    76  			break
    77  		}
    78  		if !lb && i < ll {
    79  			nn += size
    80  		} else if lb {
    81  			nn += size
    82  		}
    83  	}
    84  	if !lb {
    85  		return str[n:nn]
    86  	}
    87  	return str[n:]
    88  }
    89  
    90  // Bytes2String bytes to string
    91  func Bytes2String(b []byte) string {
    92  	return *(*string)(unsafe.Pointer(&b))
    93  }
    94  
    95  // String2Bytes string to bytes
    96  // remark: read only, the structure of runtime changes will be affected, the role of unsafe.Pointer will be changed, and it will also be affected
    97  func String2Bytes(s string) []byte {
    98  	return *(*[]byte)(unsafe.Pointer(
    99  		&struct {
   100  			string
   101  			Cap int
   102  		}{s, len(s)},
   103  	))
   104  }
   105  
   106  // Ucfirst First letters capitalize
   107  func Ucfirst(str string) string {
   108  	for i, v := range str {
   109  		return string(unicode.ToUpper(v)) + str[i+1:]
   110  	}
   111  	return ""
   112  }
   113  
   114  // Lcfirst First letters lowercase
   115  func Lcfirst(str string) string {
   116  	for i, v := range str {
   117  		return string(unicode.ToLower(v)) + str[i+1:]
   118  	}
   119  	return ""
   120  }
   121  
   122  // IsUcfirst tests whether the given byte b is in upper case
   123  func IsUcfirst(str string) bool {
   124  	b := String2Bytes(str)
   125  	if b[0] >= byte('A') && b[0] <= byte('Z') {
   126  		return true
   127  	}
   128  	return false
   129  }
   130  
   131  // IsLcfirst tests whether the given byte b is in lower case
   132  func IsLcfirst(str string) bool {
   133  	b := String2Bytes(str)
   134  	if b[0] >= byte('a') && b[0] <= byte('z') {
   135  		return true
   136  	}
   137  	return false
   138  }
   139  
   140  // TrimBOM TrimBOM
   141  func TrimBOM(fileBytes []byte) []byte {
   142  	trimmedBytes := bytes.Trim(fileBytes, "\xef\xbb\xbf")
   143  	return trimmedBytes
   144  }
   145  
   146  // SnakeCaseToCamelCase snakeCase To CamelCase: hello_world => helloWorld
   147  func SnakeCaseToCamelCase(str string, ucfirst bool, delimiter ...string) string {
   148  	if str == "" {
   149  		return ""
   150  	}
   151  	sep := "_"
   152  	if len(delimiter) > 0 {
   153  		sep = delimiter[0]
   154  	}
   155  	slice := strings.Split(str, sep)
   156  	for i := range slice {
   157  		if ucfirst || i > 0 {
   158  			slice[i] = strings.Title(slice[i])
   159  		}
   160  	}
   161  	return strings.Join(slice, "")
   162  }
   163  
   164  // CamelCaseToSnakeCase camelCase To SnakeCase helloWorld/HelloWorld => hello_world
   165  func CamelCaseToSnakeCase(str string, delimiter ...string) string {
   166  	if str == "" {
   167  		return ""
   168  	}
   169  	sep := []byte("_")
   170  	if len(delimiter) > 0 {
   171  		sep = []byte(delimiter[0])
   172  	}
   173  	strLen := len(str)
   174  	result := make([]byte, 0, strLen*2)
   175  	j := false
   176  	for i := 0; i < strLen; i++ {
   177  		char := str[i]
   178  		if i > 0 && char >= 'A' && char <= 'Z' && j {
   179  			result = append(result, sep...)
   180  		}
   181  		if char != '_' {
   182  			j = true
   183  		}
   184  		result = append(result, char)
   185  	}
   186  	return strings.ToLower(string(result))
   187  }
   188  
   189  // XSSClean clean html tag
   190  func XSSClean(str string) string {
   191  	str, _ = RegexReplaceFunc("<[\\S\\s]+?>", str, strings.ToLower)
   192  	str, _ = RegexReplace("<style[\\S\\s]+?</style>", str, "")
   193  	str, _ = RegexReplace("<script[\\S\\s]+?</script>", str, "")
   194  	str, _ = RegexReplace("<[\\S\\s]+?>", str, "")
   195  	str, _ = RegexReplace("\\s{2,}", str, " ")
   196  	return strings.TrimSpace(str)
   197  }
   198  
   199  // TrimLine TrimLine
   200  func TrimLine(s string) string {
   201  	str := strings.TrimSpace(regexp.MustCompile(`\s+`).ReplaceAllString(s, " "))
   202  	str = strings.Replace(str, " <", "<", -1)
   203  	str = strings.Replace(str, "> ", ">", -1)
   204  	return str
   205  }
   206  
   207  // TrimSpace TrimSpace
   208  func TrimSpace(s string) string {
   209  	space := [...]uint8{127, 128, 133, 160, 194, 226, 227}
   210  	well := func(s uint8) bool {
   211  		for i := range space {
   212  			if space[i] == s {
   213  				return true
   214  			}
   215  		}
   216  		return false
   217  	}
   218  	for len(s) > 0 {
   219  		if (s[0] <= 31) || s[0] <= ' ' || well(s[0]) {
   220  			s = s[1:]
   221  			continue
   222  		}
   223  		break
   224  	}
   225  	for len(s) > 0 {
   226  		if s[len(s)-1] <= ' ' || (s[len(s)-1] <= 31) || well(s[len(s)-1]) {
   227  			s = s[:len(s)-1]
   228  			continue
   229  		}
   230  		break
   231  	}
   232  	return s
   233  }