github.com/gogf/gf/v2@v2.7.4/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/gogf/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/gogf/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 }