github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xstring/xstring_mass.go (about) 1 package xstring 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 "strconv" 8 "strings" 9 ) 10 11 // ============== 12 // mass functions 13 // ============== 14 15 // Bool returns given t if given value is true, otherwise returns given f. 16 func Bool(b bool, t, f string) string { 17 if b { 18 return t 19 } 20 return f 21 } 22 23 // MaskToken masks a token string and returns the result, using given mask rune and indices for mask characters, this function also supports minus index. 24 func MaskToken(s string, mask rune, indices ...int) string { 25 return coreMaskToken(s, string(mask), true, indices...) 26 } 27 28 // MaskTokenR masks a token string and returns the result, using given mask rune and indices for non-mask characters, this function also supports minus index, 29 func MaskTokenR(s string, mask rune, indices ...int) string { 30 return coreMaskToken(s, string(mask), false, indices...) 31 } 32 33 // StringMaskToken masks a token string and returns the result, using given mask string and indices for mask characters, this function also supports minus index. 34 func StringMaskToken(s string, mask string, indices ...int) string { 35 return coreMaskToken(s, mask, true, indices...) 36 } 37 38 // StringMaskTokenR masks a token string and returns the result, using given mask string and indices for non-mask characters, this function also supports minus index, 39 func StringMaskTokenR(s string, mask string, indices ...int) string { 40 return coreMaskToken(s, mask, false, indices...) 41 } 42 43 // coreMaskToken is the core implementation of MaskToken and MaskTokenR. 44 func coreMaskToken(s string, mask string, toMask bool, indices ...int) string { 45 switch { 46 case len(s) == 0: // empty 47 return "" 48 case len(indices) == 0: // no change or full change 49 if toMask { 50 return s 51 } 52 return strings.Repeat(mask, len(s)) 53 } 54 55 length := 0 56 for range s { 57 length++ 58 } 59 newIndices := make(map[int]struct{}) // idx map 60 idxs := make([]int, 0, len(indices)) 61 for _, i := range indices { 62 if 0 <= i && i < length { 63 idxs = append(idxs, i) 64 } else if -length <= i && i < 0 { 65 idxs = append(idxs, length+i) 66 } 67 } 68 sort.Ints(idxs) 69 for _, index := range idxs { 70 newIndices[index] = struct{}{} 71 } 72 73 sb := strings.Builder{} 74 sb.Grow(len(s)) 75 // use index to write mask or character 76 for i, ch := range s { 77 _, contains := newIndices[i] 78 if (toMask && contains) || (!toMask && !contains) { 79 sb.WriteString(mask) 80 } else { 81 sb.WriteRune(ch) 82 } 83 } 84 return sb.String() 85 } 86 87 // EncodeUrlValues encodes the values (see url.Values) into url encoded form ("bar=baz&foo=quux") sorted by key with escape. 88 // The escapeFunc can be url.QueryEscape, url.PathEscape or the functions you defined, use nil for no escape. 89 func EncodeUrlValues(values map[string][]string, escapeFunc func(string) string) string { 90 keys := make([]string, 0, len(values)) 91 for k := range values { 92 keys = append(keys, k) 93 } 94 sort.Strings(keys) 95 96 sb := strings.Builder{} 97 sb.Grow(len(values) * 4) 98 for _, k := range keys { 99 key := k 100 if escapeFunc != nil { 101 key = escapeFunc(key) 102 } 103 for _, v := range values[k] { 104 val := v 105 if escapeFunc != nil { 106 val = escapeFunc(val) 107 } 108 if sb.Len() > 0 { 109 sb.WriteString("&") 110 } 111 sb.WriteString(key) // escaped 112 sb.WriteString("=") 113 sb.WriteString(val) // escaped 114 } 115 } 116 117 return sb.String() 118 } 119 120 const ( 121 panicIndexOutOfRange = "xstring: index out of range" 122 ) 123 124 // SplitAndGet returns the string item from the split result slices, this also supports minus index. 125 func SplitAndGet(s string, sep string, index int) string { 126 sp := strings.Split(s, sep) 127 l := len(sp) 128 129 if index >= 0 && index < l { 130 return sp[index] 131 } 132 if newIndex := l + index; newIndex >= 0 && newIndex < l { 133 return sp[newIndex] 134 } 135 136 panic(panicIndexOutOfRange) 137 } 138 139 // StringSliceToMap returns a string-string map from given string slice. Note that extra argument will be skipped. 140 func StringSliceToMap(args []string) map[string]string { 141 l := len(args) 142 out := make(map[string]string, l/2) 143 for i := 0; i < l; i += 2 { 144 if i+1 >= l { 145 break // ignore the extra arg 146 } 147 key, value := args[i], args[i+1] 148 out[key] = value 149 } 150 return out 151 } 152 153 // SliceToStringMap returns a string-interface{} map from given interface{} slice. Note that nil arguments and extra argument will be skipped. 154 func SliceToStringMap(args []interface{}) map[string]interface{} { 155 l := len(args) 156 out := make(map[string]interface{}, l/2) 157 158 for i := 0; i < l; i += 2 { 159 if i+1 >= l { 160 break // ignore the extra arg 161 } 162 key := "" 163 keyItf, value := args[i], args[i+1] 164 if keyItf == nil { 165 i-- 166 continue 167 } 168 if s, ok := keyItf.(string); ok { 169 key = s 170 } else if bs, ok := keyItf.([]byte); ok { 171 key = FastBtos(bs) 172 } else { 173 key = fmt.Sprintf("%v", keyItf) // %v 174 } 175 out[key] = value 176 } 177 178 return out 179 } 180 181 var ( 182 errUnsupportedVersionString = errors.New("xstring: unsupported version string") 183 ) 184 185 // SemanticVersion parses given semantic version string to (major, minor, patch) version number. Note that this function supports 186 // "1", "1.1", "1.1.1", "v1", "v1.1", "v1.1.1" format. 187 func SemanticVersion(semver string) (uint64, uint64, uint64, error) { 188 if len(semver) == 0 || (len(semver) == 1 && !IsArabicNumber(rune(semver[0]))) { 189 return 0, 0, 0, errUnsupportedVersionString 190 } 191 if semver[0] == 'v' { 192 semver = semver[1:] 193 } 194 first := strings.IndexByte(semver, '.') 195 last := strings.LastIndexByte(semver, '.') 196 if first == -1 { 197 // 1 / v1 198 p1, err1 := strconv.ParseUint(semver, 10, 64) 199 if err1 != nil { 200 return 0, 0, 0, errUnsupportedVersionString 201 } 202 return p1, 0, 0, nil 203 } 204 if first == last { 205 // 1.1 / v1.1 206 p1, err1 := strconv.ParseUint(semver[:first], 10, 64) 207 p2, err2 := strconv.ParseUint(semver[first+1:], 10, 64) 208 if err1 != nil || err2 != nil { 209 return 0, 0, 0, errUnsupportedVersionString 210 } 211 return p1, p2, 0, nil 212 } 213 // 1.1.1 / v1.1.1 214 p1, err1 := strconv.ParseUint(semver[:first], 10, 64) 215 p2, err2 := strconv.ParseUint(semver[first+1:last], 10, 64) 216 p3, err3 := strconv.ParseUint(semver[last+1:], 10, 64) 217 if err1 != nil || err2 != nil || err3 != nil { 218 return 0, 0, 0, errUnsupportedVersionString 219 } 220 return p1, p2, p3, nil 221 }