string.go 5.4 KB

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