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  }