123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- // 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"
- "math"
- "regexp"
- "strconv"
- "strings"
- "unicode"
- "github.com/gogf/gf/v2/util/grand"
- )
- var (
- // octReg is the regular expression object for checks octal string.
- octReg = regexp.MustCompile(`\\[0-7]{3}`)
- )
- // 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])
- }
- // 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`|<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("<br />")
- } else {
- br = []byte("<br>")
- }
- 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.
- // This function supports cut parameters of both english and chinese punctuations.
- // TODO: Enable custom 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)
- strRunes = []rune(str)
- )
- for _, char := range strRunes {
- switch {
- case 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
- case 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)
- case isPunctuation(char):
- wordBuf.WriteRune(char)
- if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
- current += spaceBuf.Len() + wordBuf.Len()
- _, _ = spaceBuf.WriteTo(buf)
- spaceBuf.Reset()
- _, _ = wordBuf.WriteTo(buf)
- wordBuf.Reset()
- }
- default:
- 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()
- }
- func isPunctuation(char int32) bool {
- switch char {
- // English Punctuations.
- case ';', '.', ',', ':', '~':
- return true
- // Chinese Punctuations.
- case ';', ',', '。', ':', '?', '!', '…', '、':
- return true
- default:
- return false
- }
- }
|