github.com/wangyougui/gf/v2@v2.6.5/text/gstr/gstr_convert.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package gstr
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"math"
    13  	"regexp"
    14  	"strconv"
    15  	"strings"
    16  	"unicode"
    17  
    18  	"github.com/wangyougui/gf/v2/util/grand"
    19  )
    20  
    21  var (
    22  	// octReg is the regular expression object for checks octal string.
    23  	octReg = regexp.MustCompile(`\\[0-7]{3}`)
    24  )
    25  
    26  // Chr return the ascii string of a number(0-255).
    27  //
    28  // Example:
    29  // Chr(65) -> "A"
    30  func Chr(ascii int) string {
    31  	return string([]byte{byte(ascii % 256)})
    32  }
    33  
    34  // Ord converts the first byte of a string to a value between 0 and 255.
    35  //
    36  // Example:
    37  // Chr("A") -> 65
    38  func Ord(char string) int {
    39  	return int(char[0])
    40  }
    41  
    42  // OctStr converts string container octal string to its original string,
    43  // for example, to Chinese string.
    44  //
    45  // Example:
    46  // OctStr("\346\200\241") -> 怡
    47  func OctStr(str string) string {
    48  	return octReg.ReplaceAllStringFunc(
    49  		str,
    50  		func(s string) string {
    51  			i, _ := strconv.ParseInt(s[1:], 8, 0)
    52  			return string([]byte{byte(i)})
    53  		},
    54  	)
    55  }
    56  
    57  // Reverse returns a string which is the reverse of `str`.
    58  //
    59  // Example:
    60  // Reverse("123456") -> "654321"
    61  func Reverse(str string) string {
    62  	runes := []rune(str)
    63  	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
    64  		runes[i], runes[j] = runes[j], runes[i]
    65  	}
    66  	return string(runes)
    67  }
    68  
    69  // NumberFormat formats a number with grouped thousands.
    70  // Parameter `decimals`: Sets the number of decimal points.
    71  // Parameter `decPoint`: Sets the separator for the decimal point.
    72  // Parameter `thousandsSep`: Sets the thousands' separator.
    73  // See http://php.net/manual/en/function.number-format.php.
    74  //
    75  // Example:
    76  // NumberFormat(1234.56, 2, ".", "")  -> 1234,56
    77  // NumberFormat(1234.56, 2, ",", " ") -> 1 234,56
    78  func NumberFormat(number float64, decimals int, decPoint, thousandsSep string) string {
    79  	neg := false
    80  	if number < 0 {
    81  		number = -number
    82  		neg = true
    83  	}
    84  	// Will round off
    85  	str := fmt.Sprintf("%."+strconv.Itoa(decimals)+"F", number)
    86  	prefix, suffix := "", ""
    87  	if decimals > 0 {
    88  		prefix = str[:len(str)-(decimals+1)]
    89  		suffix = str[len(str)-decimals:]
    90  	} else {
    91  		prefix = str
    92  	}
    93  	sep := []byte(thousandsSep)
    94  	n, l1, l2 := 0, len(prefix), len(sep)
    95  	// thousands sep num
    96  	c := (l1 - 1) / 3
    97  	tmp := make([]byte, l2*c+l1)
    98  	pos := len(tmp) - 1
    99  	for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 {
   100  		if l2 > 0 && n > 0 && n%3 == 0 {
   101  			for j := range sep {
   102  				tmp[pos] = sep[l2-j-1]
   103  				pos--
   104  			}
   105  		}
   106  		tmp[pos] = prefix[i]
   107  	}
   108  	s := string(tmp)
   109  	if decimals > 0 {
   110  		s += decPoint + suffix
   111  	}
   112  	if neg {
   113  		s = "-" + s
   114  	}
   115  
   116  	return s
   117  }
   118  
   119  // Shuffle randomly shuffles a string.
   120  // It considers parameter `str` as unicode string.
   121  //
   122  // Example:
   123  // Shuffle("123456") -> "325164"
   124  // Shuffle("123456") -> "231546"
   125  // ...
   126  func Shuffle(str string) string {
   127  	runes := []rune(str)
   128  	s := make([]rune, len(runes))
   129  	for i, v := range grand.Perm(len(runes)) {
   130  		s[i] = runes[v]
   131  	}
   132  	return string(s)
   133  }
   134  
   135  // HideStr replaces part of the string `str` to `hide` by `percentage` from the `middle`.
   136  // It considers parameter `str` as unicode string.
   137  func HideStr(str string, percent int, hide string) string {
   138  	array := strings.Split(str, "@")
   139  	if len(array) > 1 {
   140  		str = array[0]
   141  	}
   142  	var (
   143  		rs       = []rune(str)
   144  		length   = len(rs)
   145  		mid      = math.Floor(float64(length / 2))
   146  		hideLen  = int(math.Floor(float64(length) * (float64(percent) / 100)))
   147  		start    = int(mid - math.Floor(float64(hideLen)/2))
   148  		hideStr  = []rune("")
   149  		hideRune = []rune(hide)
   150  	)
   151  	for i := 0; i < hideLen; i++ {
   152  		hideStr = append(hideStr, hideRune...)
   153  	}
   154  	buffer := bytes.NewBuffer(nil)
   155  	buffer.WriteString(string(rs[0:start]))
   156  	buffer.WriteString(string(hideStr))
   157  	buffer.WriteString(string(rs[start+hideLen:]))
   158  	if len(array) > 1 {
   159  		buffer.WriteString("@" + array[1])
   160  	}
   161  	return buffer.String()
   162  }
   163  
   164  // Nl2Br inserts HTML line breaks(`br`|<br />) before all newlines in a string:
   165  // \n\r, \r\n, \r, \n.
   166  // It considers parameter `str` as unicode string.
   167  func Nl2Br(str string, isXhtml ...bool) string {
   168  	r, n, runes := '\r', '\n', []rune(str)
   169  	var br []byte
   170  	if len(isXhtml) > 0 && isXhtml[0] {
   171  		br = []byte("<br />")
   172  	} else {
   173  		br = []byte("<br>")
   174  	}
   175  	skip := false
   176  	length := len(runes)
   177  	var buf bytes.Buffer
   178  	for i, v := range runes {
   179  		if skip {
   180  			skip = false
   181  			continue
   182  		}
   183  		switch v {
   184  		case n, r:
   185  			if (i+1 < length) && ((v == r && runes[i+1] == n) || (v == n && runes[i+1] == r)) {
   186  				buf.Write(br)
   187  				skip = true
   188  				continue
   189  			}
   190  			buf.Write(br)
   191  		default:
   192  			buf.WriteRune(v)
   193  		}
   194  	}
   195  	return buf.String()
   196  }
   197  
   198  // WordWrap wraps a string to a given number of characters.
   199  // This function supports cut parameters of both english and chinese punctuations.
   200  // TODO: Enable custom cut parameter, see http://php.net/manual/en/function.wordwrap.php.
   201  func WordWrap(str string, width int, br string) string {
   202  	if br == "" {
   203  		br = "\n"
   204  	}
   205  	var (
   206  		current           int
   207  		wordBuf, spaceBuf bytes.Buffer
   208  		init              = make([]byte, 0, len(str))
   209  		buf               = bytes.NewBuffer(init)
   210  		strRunes          = []rune(str)
   211  	)
   212  	for _, char := range strRunes {
   213  		switch {
   214  		case char == '\n':
   215  			if wordBuf.Len() == 0 {
   216  				if current+spaceBuf.Len() > width {
   217  					current = 0
   218  				} else {
   219  					current += spaceBuf.Len()
   220  					_, _ = spaceBuf.WriteTo(buf)
   221  				}
   222  				spaceBuf.Reset()
   223  			} else {
   224  				current += spaceBuf.Len() + wordBuf.Len()
   225  				_, _ = spaceBuf.WriteTo(buf)
   226  				spaceBuf.Reset()
   227  				_, _ = wordBuf.WriteTo(buf)
   228  				wordBuf.Reset()
   229  			}
   230  			buf.WriteRune(char)
   231  			current = 0
   232  
   233  		case unicode.IsSpace(char):
   234  			if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
   235  				current += spaceBuf.Len() + wordBuf.Len()
   236  				_, _ = spaceBuf.WriteTo(buf)
   237  				spaceBuf.Reset()
   238  				_, _ = wordBuf.WriteTo(buf)
   239  				wordBuf.Reset()
   240  			}
   241  			spaceBuf.WriteRune(char)
   242  
   243  		case isPunctuation(char):
   244  			wordBuf.WriteRune(char)
   245  			if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
   246  				current += spaceBuf.Len() + wordBuf.Len()
   247  				_, _ = spaceBuf.WriteTo(buf)
   248  				spaceBuf.Reset()
   249  				_, _ = wordBuf.WriteTo(buf)
   250  				wordBuf.Reset()
   251  			}
   252  
   253  		default:
   254  			wordBuf.WriteRune(char)
   255  			if current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width {
   256  				buf.WriteString(br)
   257  				current = 0
   258  				spaceBuf.Reset()
   259  			}
   260  		}
   261  	}
   262  
   263  	if wordBuf.Len() == 0 {
   264  		if current+spaceBuf.Len() <= width {
   265  			_, _ = spaceBuf.WriteTo(buf)
   266  		}
   267  	} else {
   268  		_, _ = spaceBuf.WriteTo(buf)
   269  		_, _ = wordBuf.WriteTo(buf)
   270  	}
   271  	return buf.String()
   272  }
   273  
   274  func isPunctuation(char int32) bool {
   275  	switch char {
   276  	// English Punctuations.
   277  	case ';', '.', ',', ':', '~':
   278  		return true
   279  	// Chinese Punctuations.
   280  	case ';', ',', '。', ':', '?', '!', '…', '、':
   281  		return true
   282  	default:
   283  		return false
   284  	}
   285  }