// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gstr import ( "bytes" "fmt" "github.com/gogf/gf/v2/util/grand" "math" "regexp" "strconv" "strings" "unicode" ) // Chr return the ascii string of a number(0-255). func Chr(ascii int) string { return string([]byte{byte(ascii % 256)}) } // Ord converts the first byte of a string to a value between 0 and 255. func Ord(char string) int { return int(char[0]) } var ( // octReg is the regular expression object for checks octal string. octReg = regexp.MustCompile(`\\[0-7]{3}`) ) // OctStr converts string container octal string to its original string, // for example, to Chinese string. // Eg: `\346\200\241` -> 怡 func OctStr(str string) string { return octReg.ReplaceAllStringFunc( str, func(s string) string { i, _ := strconv.ParseInt(s[1:], 8, 0) return string([]byte{byte(i)}) }, ) } // Reverse returns a string which is the reverse of `str`. func Reverse(str string) string { runes := []rune(str) for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { runes[i], runes[j] = runes[j], runes[i] } return string(runes) } // NumberFormat formats a number with grouped thousands. // `decimals`: Sets the number of decimal points. // `decPoint`: Sets the separator for the decimal point. // `thousandsSep`: Sets the thousands' separator. // See http://php.net/manual/en/function.number-format.php. func NumberFormat(number float64, decimals int, decPoint, thousandsSep string) string { neg := false if number < 0 { number = -number neg = true } // Will round off str := fmt.Sprintf("%."+strconv.Itoa(decimals)+"F", number) prefix, suffix := "", "" if decimals > 0 { prefix = str[:len(str)-(decimals+1)] suffix = str[len(str)-decimals:] } else { prefix = str } sep := []byte(thousandsSep) n, l1, l2 := 0, len(prefix), len(sep) // thousands sep num c := (l1 - 1) / 3 tmp := make([]byte, l2*c+l1) pos := len(tmp) - 1 for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 { if l2 > 0 && n > 0 && n%3 == 0 { for j := range sep { tmp[pos] = sep[l2-j-1] pos-- } } tmp[pos] = prefix[i] } s := string(tmp) if decimals > 0 { s += decPoint + suffix } if neg { s = "-" + s } return s } // Shuffle randomly shuffles a string. // It considers parameter `str` as unicode string. func Shuffle(str string) string { runes := []rune(str) s := make([]rune, len(runes)) for i, v := range grand.Perm(len(runes)) { s[i] = runes[v] } return string(s) } // HideStr replaces part of the string `str` to `hide` by `percentage` from the `middle`. // It considers parameter `str` as unicode string. func HideStr(str string, percent int, hide string) string { array := strings.Split(str, "@") if len(array) > 1 { str = array[0] } var ( rs = []rune(str) length = len(rs) mid = math.Floor(float64(length / 2)) hideLen = int(math.Floor(float64(length) * (float64(percent) / 100))) start = int(mid - math.Floor(float64(hideLen)/2)) hideStr = []rune("") hideRune = []rune(hide) ) for i := 0; i < hideLen; i++ { hideStr = append(hideStr, hideRune...) } buffer := bytes.NewBuffer(nil) buffer.WriteString(string(rs[0:start])) buffer.WriteString(string(hideStr)) buffer.WriteString(string(rs[start+hideLen:])) if len(array) > 1 { buffer.WriteString("@" + array[1]) } return buffer.String() } // Nl2Br inserts HTML line breaks(`br`|
) before all newlines in a string: // \n\r, \r\n, \r, \n. // It considers parameter `str` as unicode string. func Nl2Br(str string, isXhtml ...bool) string { r, n, runes := '\r', '\n', []rune(str) var br []byte if len(isXhtml) > 0 && isXhtml[0] { br = []byte("
") } else { br = []byte("
") } skip := false length := len(runes) var buf bytes.Buffer for i, v := range runes { if skip { skip = false continue } switch v { case n, r: if (i+1 < length) && (v == r && runes[i+1] == n) || (v == n && runes[i+1] == r) { buf.Write(br) skip = true continue } buf.Write(br) default: buf.WriteRune(v) } } return buf.String() } // WordWrap wraps a string to a given number of characters. // TODO: Enable cut parameter, see http://php.net/manual/en/function.wordwrap.php. func WordWrap(str string, width int, br string) string { if br == "" { br = "\n" } var ( current int wordBuf, spaceBuf bytes.Buffer init = make([]byte, 0, len(str)) buf = bytes.NewBuffer(init) ) for _, char := range []rune(str) { if char == '\n' { if wordBuf.Len() == 0 { if current+spaceBuf.Len() > width { current = 0 } else { current += spaceBuf.Len() spaceBuf.WriteTo(buf) } spaceBuf.Reset() } else { current += spaceBuf.Len() + wordBuf.Len() spaceBuf.WriteTo(buf) spaceBuf.Reset() wordBuf.WriteTo(buf) wordBuf.Reset() } buf.WriteRune(char) current = 0 } else if unicode.IsSpace(char) { if spaceBuf.Len() == 0 || wordBuf.Len() > 0 { current += spaceBuf.Len() + wordBuf.Len() spaceBuf.WriteTo(buf) spaceBuf.Reset() wordBuf.WriteTo(buf) wordBuf.Reset() } spaceBuf.WriteRune(char) } else { wordBuf.WriteRune(char) if current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width { buf.WriteString(br) current = 0 spaceBuf.Reset() } } } if wordBuf.Len() == 0 { if current+spaceBuf.Len() <= width { spaceBuf.WriteTo(buf) } } else { spaceBuf.WriteTo(buf) wordBuf.WriteTo(buf) } return buf.String() }