1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
|
// Package randomstring can be used for generating different types of random strings
package randomstring
import (
"math/rand"
"strings"
"time"
)
var random = rand.New(rand.NewSource(1))
var freq = map[rune]int{
'e': 21912,
't': 16587,
'a': 14810,
'o': 14003,
'i': 13318,
'n': 12666,
's': 11450,
'r': 10977,
'h': 10795,
'd': 7874,
'l': 7253,
'u': 5246,
'c': 4943,
'm': 4761,
'f': 4200,
'y': 3853,
'w': 3819,
'g': 3693,
'p': 3316,
'b': 2715,
'v': 2019,
'k': 1257,
'x': 315,
'q': 205,
'j': 188,
'z': 128,
}
var freqVowel = map[rune]int{
'e': 21912,
'a': 14810,
'o': 14003,
'i': 13318,
'u': 5246,
}
var freqCons = map[rune]int{
't': 16587,
'n': 12666,
's': 11450,
'r': 10977,
'h': 10795,
'd': 7874,
'l': 7253,
'c': 4943,
'm': 4761,
'f': 4200,
'y': 3853,
'w': 3819,
'g': 3693,
'p': 3316,
'b': 2715,
'v': 2019,
'k': 1257,
'x': 315,
'q': 205,
'j': 188,
'z': 128,
}
// freqsum is a sum of all the frequencies in the freq map
var freqsum = func() int {
n := 0
for _, v := range freq {
n += v
}
return n
}()
// freqsumVowel is a sum of all the frequencies in the freqVowel map
var freqsumVowel = func() int {
n := 0
for _, v := range freqVowel {
n += v
}
return n
}()
// freqsumCons is a sum of all the frequencies in the freqCons map
var freqsumCons = func() int {
n := 0
for _, v := range freqCons {
n += v
}
return n
}()
// PickLetter will pick a letter, weighted by the frequency table
func PickLetter() rune {
target := random.Intn(freqsum)
selected := 'a'
n := 0
for k, v := range freq {
n += v
if n > target {
selected = k
break
}
}
return selected
}
// PickVowel will pick a vowel, weighted by the frequency table
func PickVowel() rune {
target := random.Intn(freqsumVowel)
selected := 'a'
n := 0
for k, v := range freqVowel {
n += v
if n > target {
selected = k
break
}
}
return selected
}
// PickCons will pick a consonant, weighted by the frequency table
func PickCons() rune {
target := random.Intn(freqsumCons)
selected := 't'
n := 0
for k, v := range freqCons {
n += v
if n > target {
selected = k
break
}
}
return selected
}
// Seed the random number generator in one of many possible ways.
func Seed() {
random = rand.New(rand.NewSource(time.Now().UTC().UnixNano() + 1337))
}
// String generates a random string of a given length.
func String(length int) string {
b := make([]byte, length)
for i := 0; i < length; i++ {
b[i] = byte(random.Int63() & 0xff)
}
return string(b)
}
// StringNoAlloc generates a random string in the given byte slice,
// but does not allocate memory with "make".
func StringNoAlloc(placeholder []byte) {
for i := 0; i < len(placeholder); i++ {
(placeholder)[i] = byte(random.Int63() & 0xff)
}
}
// EnglishFrequencyString returns a random string that uses the letter frequency of English,
// ref: http://pi.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html
func EnglishFrequencyString(length int) string {
var sb strings.Builder
for i := 0; i < length; i++ {
sb.WriteRune(PickLetter())
}
return sb.String()
}
/*HumanFriendlyString generates a random, but human-friendly, string of
* the given length. It should be possible to read out loud and send in an email
* without problems. The string alternates between vowels and consontants.
*
* Google Translate believes the output is Samoan.
*
* Example output for length 7: rabunor
*/
func HumanFriendlyString(length int) string {
const (
someVowels = "aeoiu" // a selection of vowels. email+browsers didn't like "æøå" too much
someConsonants = "bdfgklmnoprstv" // a selection of consonants
moreLetters = "chjqwxyz" // the rest of the letters from a-z
)
vowelOffset := random.Intn(2)
vowelDistribution := 2
b := make([]byte, length)
for i := 0; i < length; i++ {
again:
if (i+vowelOffset)%vowelDistribution == 0 {
b[i] = someVowels[random.Intn(len(someVowels))]
} else if random.Intn(100) > 0 { // 99 of 100 times
b[i] = someConsonants[random.Intn(len(someConsonants))]
// Don't repeat
if i >= 1 && b[i] == b[i-1] {
// Also use more vowels
vowelDistribution = 1
// Then try again
goto again
}
} else {
b[i] = moreLetters[random.Intn(len(moreLetters))]
// Don't repeat
if i >= 1 && b[i] == b[i-1] {
// Also use more vowels
vowelDistribution = 1
// Then try again
goto again
}
}
// Avoid three letters in a row
if i >= 2 && b[i] == b[i-2] {
// Then try again
goto again
}
}
return string(b)
}
// CookieFriendlyString generates a random, but cookie-friendly, string of the given length.
func CookieFriendlyString(length int) string {
const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := 0; i < length; i++ {
b[i] = allowed[random.Intn(len(allowed))]
}
return string(b)
}
// CookieFriendlyStringNoAlloc generates a random, but cookie-friendly, string.
// The bytes of the string are stored in the given byte slice.
func CookieFriendlyStringNoAlloc(placeholder []byte) {
const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
for i := 0; i < len(placeholder); i++ {
(placeholder)[i] = allowed[random.Intn(len(allowed))]
}
}
// CookieFriendlyBytes generates a random, but cookie-friendly, byte slice of the given length.
func CookieFriendlyBytes(length int) []byte {
const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := 0; i < length; i++ {
b[i] = allowed[random.Intn(len(allowed))]
}
return b
}
/* HumanFriendlyEnglishString generates a random, but human-friendly, string of
* the given length. It should be possible to read out loud and send in an email
* without problems. The string alternates between vowels and consontants.
*
* The vowels and consontants are wighted by the frequency table
*/
func HumanFriendlyEnglishString(length int) string {
vowelOffset := random.Intn(2)
vowelDistribution := 2
b := make([]byte, length)
for i := 0; i < length; i++ {
again:
if (i+vowelOffset)%vowelDistribution == 0 {
b[i] = byte(PickVowel())
} else if random.Intn(100) > 0 { // 99 of 100 times
b[i] = byte(PickCons())
// Don't repeat
if i >= 1 && b[i] == b[i-1] {
// Also use more vowels
vowelDistribution = 1
// Then try again
goto again
}
} else {
b[i] = byte(PickLetter())
// Don't repeat
if i >= 1 && b[i] == b[i-1] {
// Also use more vowels
vowelDistribution = 1
// Then try again
goto again
}
}
// Avoid three letters in a row
if i >= 2 && b[i] == b[i-2] {
// Then try again
goto again
}
}
return string(b)
}
|