package stringx import ( "errors" "unicode" "github.com/zeromicro/go-zero/core/lang" ) var ( // ErrInvalidStartPosition is an error that indicates the start position is invalid. ErrInvalidStartPosition = errors.New("start position is invalid") // ErrInvalidStopPosition is an error that indicates the stop position is invalid. ErrInvalidStopPosition = errors.New("stop position is invalid") ) // Contains checks if str is in list. func Contains(list []string, str string) bool { for _, each := range list { if each == str { return true } } return false } // Filter filters chars from s with given filter function. func Filter(s string, filter func(r rune) bool) string { var n int chars := []rune(s) for i, x := range chars { if n < i { chars[n] = x } if !filter(x) { n++ } } return string(chars[:n]) } // FirstN returns first n runes from s. func FirstN(s string, n int, ellipsis ...string) string { var i int for j := range s { if i == n { ret := s[:j] for _, each := range ellipsis { ret += each } return ret } i++ } return s } // HasEmpty checks if there are empty strings in args. func HasEmpty(args ...string) bool { for _, arg := range args { if len(arg) == 0 { return true } } return false } // Join joins any number of elements into a single string, separating them with given sep. // Empty elements are ignored. However, if the argument list is empty or all its elements are empty, // Join returns an empty string. func Join(sep byte, elem ...string) string { var size int for _, e := range elem { size += len(e) } if size == 0 { return "" } buf := make([]byte, 0, size+len(elem)-1) for _, e := range elem { if len(e) == 0 { continue } if len(buf) > 0 { buf = append(buf, sep) } buf = append(buf, e...) } return string(buf) } // NotEmpty checks if all strings are not empty in args. func NotEmpty(args ...string) bool { return !HasEmpty(args...) } // Remove removes given strs from strings. func Remove(strings []string, strs ...string) []string { out := append([]string(nil), strings...) for _, str := range strs { var n int for _, v := range out { if v != str { out[n] = v n++ } } out = out[:n] } return out } // Reverse reverses s. func Reverse(s string) string { runes := []rune(s) for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 { runes[from], runes[to] = runes[to], runes[from] } return string(runes) } // Substr returns runes between start and stop [start, stop) // regardless of the chars are ascii or utf8. func Substr(str string, start, stop int) (string, error) { rs := []rune(str) length := len(rs) if start < 0 || start > length { return "", ErrInvalidStartPosition } if stop < 0 || stop > length { return "", ErrInvalidStopPosition } return string(rs[start:stop]), nil } // TakeOne returns valid string if not empty or later one. func TakeOne(valid, or string) string { if len(valid) > 0 { return valid } return or } // TakeWithPriority returns the first not empty result from fns. func TakeWithPriority(fns ...func() string) string { for _, fn := range fns { val := fn() if len(val) > 0 { return val } } return "" } // ToCamelCase returns the string that converts the first letter to lowercase. func ToCamelCase(s string) string { for i, v := range s { return string(unicode.ToLower(v)) + s[i+1:] } return "" } // Union merges the strings in first and second. func Union(first, second []string) []string { set := make(map[string]lang.PlaceholderType) for _, each := range first { set[each] = lang.Placeholder } for _, each := range second { set[each] = lang.Placeholder } merged := make([]string, 0, len(set)) for k := range set { merged = append(merged, k) } return merged }