gstr_convert.go 6.3 KB

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