diff --git a/README.md b/README.md index d2c2a134..df1d2863 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ Supported math helpers: Supported helpers for strings: +- [RandomString](#randomstring) - [Substring](#substring) - [ChunkString](#chunkstring) - [RuneLength](#runelength) @@ -1207,6 +1208,17 @@ sum := lo.SumBy(strings, func(item string) int { [[play](https://go.dev/play/p/Dz_a_7jN_ca)] +### RandomString + +Returns a random string of the specified length and made of the specified charset. + +```go +str := lo.RandomString(5, lo.LettersCharset) +// example: "eIGbt" +``` + +[[play](https://go.dev/play/p/rRseOQVVum4)] + ### Substring Return part of a string. diff --git a/string.go b/string.go index a63167cb..dfe1050b 100644 --- a/string.go +++ b/string.go @@ -1,9 +1,38 @@ package lo import ( + "math/rand" "unicode/utf8" ) +var ( + LowerCaseLettersCharset = []rune("abcdefghijklmnopqrstuvwxyz") + UpperCaseLettersCharset = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + LettersCharset = append(LowerCaseLettersCharset, UpperCaseLettersCharset...) + NumbersCharset = []rune("0123456789") + AlphanumericCharset = append(LettersCharset, NumbersCharset...) + SpecialCharset = []rune("!@#$%^&*()_+-=[]{}|;':\",./<>?") + AllCharset = append(AlphanumericCharset, SpecialCharset...) +) + +// RandomString return a random string. +// Play: https://go.dev/play/p/rRseOQVVum4 +func RandomString(size int, charset []rune) string { + if size <= 0 { + panic("lo.RandomString: Size parameter must be greater than 0") + } + if len(charset) <= 0 { + panic("lo.RandomString: Charset parameter must not be empty") + } + + b := make([]rune, size) + possibleCharactersCount := len(charset) + for i := range b { + b[i] = charset[rand.Intn(possibleCharactersCount)] + } + return string(b) +} + // Substring return part of a string. // Play: https://go.dev/play/p/TQlxQi82Lu1 func Substring[T ~string](str T, offset int, length uint) T { diff --git a/string_test.go b/string_test.go index 02a64160..c423c351 100644 --- a/string_test.go +++ b/string_test.go @@ -2,11 +2,35 @@ package lo import ( "math" + "math/rand" "testing" + "time" "github.com/stretchr/testify/assert" ) +func TestRandomString(t *testing.T) { + t.Parallel() + is := assert.New(t) + + rand.Seed(time.Now().UnixNano()) + + str1 := RandomString(100, LowerCaseLettersCharset) + is.Equal(100, RuneLength(str1)) + is.Subset(LowerCaseLettersCharset, []rune(str1)) + + str2 := RandomString(100, LowerCaseLettersCharset) + is.NotEqual(str1, str2) + + noneUtf8Charset := []rune("明1好休2林森") + str3 := RandomString(100, noneUtf8Charset) + is.Equal(100, RuneLength(str3)) + is.Subset(noneUtf8Charset, []rune(str3)) + + is.PanicsWithValue("lo.RandomString: Charset parameter must not be empty", func() { RandomString(100, []rune{}) }) + is.PanicsWithValue("lo.RandomString: Size parameter must be greater than 0", func() { RandomString(0, LowerCaseLettersCharset) }) +} + func TestChunkString(t *testing.T) { t.Parallel() is := assert.New(t)