package strutil import ( "fmt" "regexp" "strings" "unicode" ) /************************************************************* * change string case *************************************************************/ // methods aliases var ( UpWords = UpperWord LoFirst = LowerFirst UpFirst = UpperFirst Snake = SnakeCase ) // Title alias of the strings.ToTitle() func Title(s string) string { return strings.ToTitle(s) } // Lower alias of the strings.ToLower() func Lower(s string) string { return strings.ToLower(s) } // Lowercase alias of the strings.ToLower() func Lowercase(s string) string { return strings.ToLower(s) } // Upper alias of the strings.ToUpper() func Upper(s string) string { return strings.ToUpper(s) } // Uppercase alias of the strings.ToUpper() func Uppercase(s string) string { return strings.ToUpper(s) } // UpperWord Change the first character of each word to uppercase func UpperWord(s string) string { if len(s) == 0 { return s } if len(s) == 1 { return strings.ToUpper(s) } inWord := true buf := make([]byte, 0, len(s)) i := 0 rs := []rune(s) if RuneIsLower(rs[i]) { buf = append(buf, []byte(string(unicode.ToUpper(rs[i])))...) } else { buf = append(buf, []byte(string(rs[i]))...) } for j := i + 1; j < len(rs); j++ { if !RuneIsWord(rs[i]) && RuneIsWord(rs[j]) { inWord = false } if RuneIsLower(rs[j]) && !inWord { buf = append(buf, []byte(string(unicode.ToUpper(rs[j])))...) inWord = true } else { buf = append(buf, []byte(string(rs[j]))...) } if RuneIsWord(rs[j]) { inWord = true } i++ } return string(buf) } // LowerFirst lower first char func LowerFirst(s string) string { if len(s) == 0 { return s } rs := []rune(s) f := rs[0] if 'A' <= f && f <= 'Z' { return string(unicode.ToLower(f)) + string(rs[1:]) } return s } // UpperFirst upper first char func UpperFirst(s string) string { if len(s) == 0 { return s } rs := []rune(s) f := rs[0] if 'a' <= f && f <= 'z' { return string(unicode.ToUpper(f)) + string(rs[1:]) } return s } // SnakeCase convert. eg "RangePrice" -> "range_price" func SnakeCase(s string, sep ...string) string { sepChar := "_" if len(sep) > 0 { sepChar = sep[0] } str := toSnakeReg.ReplaceAllStringFunc(s, func(s string) string { return sepChar + LowerFirst(s) }) return strings.TrimLeft(str, sepChar) } // Camel alias of the CamelCase func Camel(s string, sep ...string) string { return CamelCase(s, sep...) } // CamelCase convert string to camel case. // // Support: // // "range_price" -> "rangePrice" // "range price" -> "rangePrice" // "range-price" -> "rangePrice" func CamelCase(s string, sep ...string) string { sepChar := "_" if len(sep) > 0 { sepChar = sep[0] } // Not contains sep char if !strings.Contains(s, sepChar) { return s } // Get regexp instance rgx, ok := toCamelRegs[sepChar] if !ok { rgx = regexp.MustCompile(regexp.QuoteMeta(sepChar) + "+[a-zA-Z]") } return rgx.ReplaceAllStringFunc(s, func(s string) string { s = strings.TrimLeft(s, sepChar) return UpperFirst(s) }) } // // Indent format multi line text // from package: github.com/kr/text // // Indent inserts prefix at the beginning of each non-empty line of s. The // end-of-line marker is NL. func Indent(s, prefix string) string { return string(IndentBytes([]byte(s), []byte(prefix))) } // IndentBytes inserts prefix at the beginning of each non-empty line of b. // The end-of-line marker is NL. func IndentBytes(b, prefix []byte) []byte { if len(b) == 0 { return b } bol := true res := make([]byte, 0, len(b)+len(prefix)*4) for _, c := range b { if bol && c != '\n' { res = append(res, prefix...) } res = append(res, c) bol = c == '\n' } return res } // Replaces replace multi strings // // pairs: {old1: new1, old2: new2, ...} // // Can also use: // // strings.NewReplacer("old1", "new1", "old2", "new2").Replace(str) func Replaces(str string, pairs map[string]string) string { return NewReplacer(pairs).Replace(str) } // ReplaceVars replaces simple variables in a string. format: {varName} // // Usage: // strutil.ReplaceVars("{name}, age is {age}", map[string]string{ // "name": "Joe", // "age": "18" // }) func ReplaceVars(s string, vars map[string]string) string { if !ContainsByte(s, '{') { return s } // format var name to {name} pairs := make(map[string]string) for k, v := range vars { vName := "{" + k + "}" pairs[vName] = v } return NewReplacer(pairs).Replace(s) } // NewReplacer instance func NewReplacer(pairs map[string]string) *strings.Replacer { ss := make([]string, len(pairs)*2) for old, newVal := range pairs { ss = append(ss, old, newVal) } return strings.NewReplacer(ss...) } // WrapTag for given string. func WrapTag(s, tag string) string { if s == "" { return s } return fmt.Sprintf("<%s>%s", tag, s, tag) }