Skip to content

Instantly share code, notes, and snippets.

@neumachen
Forked from mfojtik/generator.go
Created December 30, 2016 10:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neumachen/adc5963d8058ffb55651ee055fad13fb to your computer and use it in GitHub Desktop.
Save neumachen/adc5963d8058ffb55651ee055fad13fb to your computer and use it in GitHub Desktop.
Simple generator for Golang
package main
import (
"fmt"
"log"
"math/rand"
"regexp"
"strconv"
"strings"
"time"
)
const (
Alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Numerals = "0123456789"
Ascii = Alphabet + Numerals + "~!@#$%^&*()-_+={}[]\\|<,>.?/\"';:`"
)
type GeneratorExprRanges [][]byte
func seedAndReturnRandom(n int) int {
return rand.Intn(n)
}
func alphabetSlice(from, to byte) (string, error) {
leftPos := strings.Index(Ascii, string(from))
rightPos := strings.LastIndex(Ascii, string(to))
if leftPos > rightPos {
return "", fmt.Errorf("Invalid range specified: %s-%s", string(from), string(to))
}
return Ascii[leftPos:rightPos], nil
}
func replaceWithGenerated(s *string, expresion string, ranges [][]byte, length int) error {
var alphabet string
for _, r := range ranges {
switch string(r[0]) + string(r[1]) {
case `\w`:
alphabet += Ascii
case `\d`:
alphabet += Numerals
default:
if slice, err := alphabetSlice(r[0], r[1]); err != nil {
return err
} else {
alphabet += slice
}
}
}
if len(alphabet) == 0 {
return fmt.Errorf("Empty range in expresion: %s", expresion)
}
result := make([]byte, length, length)
for i := 0; i <= length-1; i++ {
result[i] = alphabet[seedAndReturnRandom(len(alphabet))]
}
*s = strings.Replace(*s, expresion, string(result), 1)
return nil
}
func findExpresionPos(s string) GeneratorExprRanges {
rangeExp, _ := regexp.Compile(`([\\]?[a-zA-Z0-9]\-?[a-zA-Z0-9]?)`)
matches := rangeExp.FindAllStringIndex(s, -1)
result := make(GeneratorExprRanges, len(matches), len(matches))
for i, r := range matches {
result[i] = []byte{s[r[0]], s[r[1]-1]}
}
return result
}
func rangesAndLength(s string) (string, int, error) {
expr := s[0:strings.LastIndex(s, "{")]
length, err := parseLength(s)
return expr, length, err
}
func parseLength(s string) (int, error) {
lengthStr := string(s[strings.LastIndex(s, "{")+1 : len(s)-1])
if l, err := strconv.Atoi(lengthStr); err != nil {
return 0, fmt.Errorf("Unable to parse length from %v", s)
} else {
return l, nil
}
}
func Generate(template string) (string, error) {
result := template
generatorsExp, _ := regexp.Compile(`\[([a-zA-Z0-9\-\\]+)\](\{([0-9]+)\})`)
matches := generatorsExp.FindAllStringIndex(template, -1)
for _, r := range matches {
ranges, length, err := rangesAndLength(template[r[0]:r[1]])
if err != nil {
return "", err
}
positions := findExpresionPos(ranges)
if err := replaceWithGenerated(&result, template[r[0]:r[1]], positions, length); err != nil {
return "", err
}
}
return result, nil
}
func main() {
rand.Seed(time.Now().UnixNano())
// Generate 8 character long random string that contains *all* Ascii
// characters (See Ascii const)
result, _ := Generate(`foo[\w]{8}bar`)
log.Printf("result0=%v", result)
// Generate 3 character long random suffix using just lowercase alpha+numberic
// characters
result, _ = Generate(`admin[a-z0-9]{3}`)
log.Printf("result1=%v", result)
result, _ = Generate(`admin[a-z0-9]{3}something[\w]{3}`)
log.Printf("result1=%v", result)
// Generate 12 character long random password combining all alphabetic characters
// and numeric characters
result, _ = Generate(`pass[a-zA-Z0-9]{12}`)
log.Printf("result2=%v", result)
// Generate 8 character long password by using alphabetic characters
// lowercase + uppercase
result, _ = Generate(`pass[a-Z]{8}`)
log.Printf("result3=%v", result)
// Invalid range error
result, err := Generate(`pass[z-a]{8}`)
log.Printf("result4=%v; err=%v", result, err)
// Generate 8 random numeric characters
result, _ = Generate(`foo[\d]{8}bar`)
log.Printf("result5=%v", result)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment