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 }