string.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Copyright 2013 com authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // 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, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package com
  15. import (
  16. "bytes"
  17. "crypto/aes"
  18. "crypto/cipher"
  19. "crypto/rand"
  20. "encoding/base64"
  21. "errors"
  22. "io"
  23. r "math/rand"
  24. "strconv"
  25. "strings"
  26. "time"
  27. "unicode"
  28. "unicode/utf8"
  29. )
  30. // AESEncrypt encrypts text and given key with AES.
  31. func AESEncrypt(key, text []byte) ([]byte, error) {
  32. block, err := aes.NewCipher(key)
  33. if err != nil {
  34. return nil, err
  35. }
  36. b := base64.StdEncoding.EncodeToString(text)
  37. ciphertext := make([]byte, aes.BlockSize+len(b))
  38. iv := ciphertext[:aes.BlockSize]
  39. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  40. return nil, err
  41. }
  42. cfb := cipher.NewCFBEncrypter(block, iv)
  43. cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
  44. return ciphertext, nil
  45. }
  46. // AESDecrypt decrypts text and given key with AES.
  47. func AESDecrypt(key, text []byte) ([]byte, error) {
  48. block, err := aes.NewCipher(key)
  49. if err != nil {
  50. return nil, err
  51. }
  52. if len(text) < aes.BlockSize {
  53. return nil, errors.New("ciphertext too short")
  54. }
  55. iv := text[:aes.BlockSize]
  56. text = text[aes.BlockSize:]
  57. cfb := cipher.NewCFBDecrypter(block, iv)
  58. cfb.XORKeyStream(text, text)
  59. data, err := base64.StdEncoding.DecodeString(string(text))
  60. if err != nil {
  61. return nil, err
  62. }
  63. return data, nil
  64. }
  65. // IsLetter returns true if the 'l' is an English letter.
  66. func IsLetter(l uint8) bool {
  67. n := (l | 0x20) - 'a'
  68. if n >= 0 && n < 26 {
  69. return true
  70. }
  71. return false
  72. }
  73. // Expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match.
  74. func Expand(template string, match map[string]string, subs ...string) string {
  75. var p []byte
  76. var i int
  77. for {
  78. i = strings.Index(template, "{")
  79. if i < 0 {
  80. break
  81. }
  82. p = append(p, template[:i]...)
  83. template = template[i+1:]
  84. i = strings.Index(template, "}")
  85. if s, ok := match[template[:i]]; ok {
  86. p = append(p, s...)
  87. } else {
  88. j, _ := strconv.Atoi(template[:i])
  89. if j >= len(subs) {
  90. p = append(p, []byte("Missing")...)
  91. } else {
  92. p = append(p, subs[j]...)
  93. }
  94. }
  95. template = template[i+1:]
  96. }
  97. p = append(p, template...)
  98. return string(p)
  99. }
  100. // Reverse s string, support unicode
  101. func Reverse(s string) string {
  102. n := len(s)
  103. runes := make([]rune, n)
  104. for _, rune := range s {
  105. n--
  106. runes[n] = rune
  107. }
  108. return string(runes[n:])
  109. }
  110. // RandomCreateBytes generate random []byte by specify chars.
  111. func RandomCreateBytes(n int, alphabets ...byte) []byte {
  112. const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  113. var bytes = make([]byte, n)
  114. var randby bool
  115. if num, err := rand.Read(bytes); num != n || err != nil {
  116. r.Seed(time.Now().UnixNano())
  117. randby = true
  118. }
  119. for i, b := range bytes {
  120. if len(alphabets) == 0 {
  121. if randby {
  122. bytes[i] = alphanum[r.Intn(len(alphanum))]
  123. } else {
  124. bytes[i] = alphanum[b%byte(len(alphanum))]
  125. }
  126. } else {
  127. if randby {
  128. bytes[i] = alphabets[r.Intn(len(alphabets))]
  129. } else {
  130. bytes[i] = alphabets[b%byte(len(alphabets))]
  131. }
  132. }
  133. }
  134. return bytes
  135. }
  136. // ToSnakeCase can convert all upper case characters in a string to
  137. // underscore format.
  138. //
  139. // Some samples.
  140. // "FirstName" => "first_name"
  141. // "HTTPServer" => "http_server"
  142. // "NoHTTPS" => "no_https"
  143. // "GO_PATH" => "go_path"
  144. // "GO PATH" => "go_path" // space is converted to underscore.
  145. // "GO-PATH" => "go_path" // hyphen is converted to underscore.
  146. //
  147. // From https://github.com/huandu/xstrings
  148. func ToSnakeCase(str string) string {
  149. if len(str) == 0 {
  150. return ""
  151. }
  152. buf := &bytes.Buffer{}
  153. var prev, r0, r1 rune
  154. var size int
  155. r0 = '_'
  156. for len(str) > 0 {
  157. prev = r0
  158. r0, size = utf8.DecodeRuneInString(str)
  159. str = str[size:]
  160. switch {
  161. case r0 == utf8.RuneError:
  162. buf.WriteByte(byte(str[0]))
  163. case unicode.IsUpper(r0):
  164. if prev != '_' {
  165. buf.WriteRune('_')
  166. }
  167. buf.WriteRune(unicode.ToLower(r0))
  168. if len(str) == 0 {
  169. break
  170. }
  171. r0, size = utf8.DecodeRuneInString(str)
  172. str = str[size:]
  173. if !unicode.IsUpper(r0) {
  174. buf.WriteRune(r0)
  175. break
  176. }
  177. // find next non-upper-case character and insert `_` properly.
  178. // it's designed to convert `HTTPServer` to `http_server`.
  179. // if there are more than 2 adjacent upper case characters in a word,
  180. // treat them as an abbreviation plus a normal word.
  181. for len(str) > 0 {
  182. r1 = r0
  183. r0, size = utf8.DecodeRuneInString(str)
  184. str = str[size:]
  185. if r0 == utf8.RuneError {
  186. buf.WriteRune(unicode.ToLower(r1))
  187. buf.WriteByte(byte(str[0]))
  188. break
  189. }
  190. if !unicode.IsUpper(r0) {
  191. if r0 == '_' || r0 == ' ' || r0 == '-' {
  192. r0 = '_'
  193. buf.WriteRune(unicode.ToLower(r1))
  194. } else {
  195. buf.WriteRune('_')
  196. buf.WriteRune(unicode.ToLower(r1))
  197. buf.WriteRune(r0)
  198. }
  199. break
  200. }
  201. buf.WriteRune(unicode.ToLower(r1))
  202. }
  203. if len(str) == 0 || r0 == '_' {
  204. buf.WriteRune(unicode.ToLower(r0))
  205. break
  206. }
  207. default:
  208. if r0 == ' ' || r0 == '-' {
  209. r0 = '_'
  210. }
  211. buf.WriteRune(r0)
  212. }
  213. }
  214. return buf.String()
  215. }