237 lines
4.8 KiB
Go
237 lines
4.8 KiB
Go
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</%s>", tag, s, tag)
|
|
}
|