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