stringutils.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package stringutils2
  15. import (
  16. "crypto/md5"
  17. "encoding/hex"
  18. "fmt"
  19. "math/rand"
  20. "strconv"
  21. "strings"
  22. "time"
  23. )
  24. func GetMD5Hash(text string) string {
  25. hasher := md5.New()
  26. hasher.Write([]byte(text))
  27. return hex.EncodeToString(hasher.Sum(nil))
  28. }
  29. func EscapeString(str string, pairs [][]string) string {
  30. if len(pairs) == 0 {
  31. pairs = [][]string{
  32. {"\\", `\\`},
  33. {"\n", `\n`},
  34. {"\r", `\r`},
  35. {"\t", `\t`},
  36. {`"`, `\"`},
  37. {"'", `\'`},
  38. {"$", `\$`},
  39. }
  40. }
  41. for _, pair := range pairs {
  42. k, v := pair[0], pair[1]
  43. str = strings.Replace(str, k, v, -1)
  44. }
  45. return str
  46. }
  47. func EscapeEchoString(str string) (string, error) {
  48. pairs := [][]string{
  49. {"\\", `\\`},
  50. {"\n", `\n`},
  51. {"\r", `\r`},
  52. {"\t", `\t`},
  53. {`"`, `\"`},
  54. }
  55. innerPairs := [][]string{
  56. {"\\", `\\`},
  57. {"\n", `\n`},
  58. {"\r", `\r`},
  59. {"\t", `\t`},
  60. {`"`, `\"`},
  61. {"$", `\$`},
  62. }
  63. segs, err := SplitByQuotation(str)
  64. if err != nil {
  65. return "", err
  66. }
  67. ret := ""
  68. for idx := 0; idx < len(segs); idx++ {
  69. s := EscapeString(segs[idx], innerPairs)
  70. if idx%2 == 1 {
  71. s = EscapeString(segs[idx], pairs)
  72. s = `\"` + EscapeString(s, innerPairs) + `\"`
  73. }
  74. ret += s
  75. }
  76. return ret, nil
  77. }
  78. func findQuotationPos(line string, offset int) int {
  79. if offset > len(line) {
  80. return -1
  81. }
  82. subStr := line[offset:]
  83. pos := strings.Index(subStr, `"`)
  84. if pos < 0 {
  85. return pos
  86. }
  87. pos += offset
  88. if pos > 0 && line[pos-1] == '\\' {
  89. return findQuotationPos(line, pos+1)
  90. }
  91. return pos
  92. }
  93. func SplitByQuotation(line string) ([]string, error) {
  94. segs := []string{}
  95. offset := 0
  96. for offset < len(line) {
  97. pos := findQuotationPos(line, offset)
  98. if pos < 0 {
  99. segs = append(segs, line[offset:])
  100. offset = len(line)
  101. } else {
  102. if pos == offset {
  103. offset += 1
  104. } else {
  105. segs = append(segs, line[offset:pos])
  106. offset = pos + 1
  107. }
  108. pos = findQuotationPos(line, offset)
  109. if pos < 0 {
  110. return nil, fmt.Errorf("Unpaired quotations: %s", line[offset:])
  111. } else {
  112. segs = append(segs, line[offset:pos])
  113. offset = pos + 1
  114. }
  115. }
  116. }
  117. return segs, nil
  118. }
  119. func GetCharTypeCount(str string) int {
  120. digitIdx := 0
  121. lowerIdx := 1
  122. upperIdx := 2
  123. otherIdx := 3
  124. complexity := make([]int, 4)
  125. for _, b := range []byte(str) {
  126. if b >= '0' && b <= '9' {
  127. complexity[digitIdx] += 1
  128. } else if b >= 'a' && b <= 'z' {
  129. complexity[lowerIdx] += 1
  130. } else if b >= 'A' && b <= 'Z' {
  131. complexity[upperIdx] += 1
  132. } else {
  133. complexity[otherIdx] += 1
  134. }
  135. }
  136. ret := 0
  137. for i := range complexity {
  138. if complexity[i] > 0 {
  139. ret += 1
  140. }
  141. }
  142. return ret
  143. }
  144. // Qcloud: 1-128个英文字母、数字和+=,.@_-
  145. // Aws: 请使用字母数字和‘+=,.@-_’字符。 最长 64 个字符
  146. // Common: 1-64个字符, 数字字母或 +=,.@-_
  147. func GenerateRoleName(roleName string) string {
  148. ret := ""
  149. for _, s := range roleName {
  150. if (s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || strings.Contains("+=,.@-_", string(s)) {
  151. ret += string(s)
  152. }
  153. }
  154. if len(ret) == 0 {
  155. return func(length int) string {
  156. bytes := []byte("23456789abcdefghijkmnpqrstuvwxyz")
  157. result := []byte{}
  158. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  159. for i := 0; i < length; i++ {
  160. result = append(result, bytes[r.Intn(len(bytes))])
  161. }
  162. return "role-" + string(result)
  163. }(12)
  164. }
  165. if len(ret) > 64 {
  166. return ret[:64]
  167. }
  168. return ret
  169. }
  170. func FilterEmpty(input []string) []string {
  171. ret := make([]string, 0)
  172. for i := range input {
  173. if len(input[i]) > 0 {
  174. ret = append(ret, input[i])
  175. }
  176. }
  177. return ret
  178. }
  179. func PrettyFloat(f float64, precision int) string {
  180. fstr := strconv.FormatFloat(f, 'f', -1, 64)
  181. dotPos := strings.Index(fstr, ".")
  182. if dotPos < 0 {
  183. return fstr
  184. }
  185. neg := false
  186. if fstr[0] == '-' {
  187. neg = true
  188. fstr = fstr[1:]
  189. dotPos -= 1
  190. }
  191. numPart, _ := strconv.ParseInt(fstr[:dotPos], 10, 64)
  192. prePartStr := fstr[dotPos+1:]
  193. if numPart == 0 {
  194. nonZeroPos := 0
  195. for prePartStr[nonZeroPos] == '0' {
  196. nonZeroPos += 1
  197. }
  198. precision += nonZeroPos
  199. }
  200. if precision < len(prePartStr) {
  201. prePart, _ := strconv.ParseInt(prePartStr[:precision], 10, 64)
  202. if prePartStr[precision] > '4' {
  203. // rounding up
  204. prePart += 1
  205. }
  206. prePartStr = fmt.Sprintf(fmt.Sprintf("%%.%dd", precision), prePart)
  207. if len(prePartStr) > precision {
  208. prePartStr = prePartStr[1:]
  209. numPart += 1
  210. }
  211. }
  212. for len(prePartStr) > 0 && prePartStr[len(prePartStr)-1] == '0' {
  213. prePartStr = prePartStr[0 : len(prePartStr)-1]
  214. }
  215. ret := strconv.FormatInt(numPart, 10)
  216. if len(prePartStr) > 0 {
  217. ret += "." + prePartStr
  218. }
  219. if neg {
  220. ret = "-" + ret
  221. }
  222. return ret
  223. }