From c9a8c70ee6c0a26a8b851d2c94bd4abd2a27963c Mon Sep 17 00:00:00 2001 From: dudaodong Date: Wed, 4 Sep 2024 10:13:36 +0800 Subject: [PATCH] feat: merge some new functions from v2 branch --- docs/random.md | 165 ++++++++++++++++++++++++++++ docs/random_zh-CN.md | 165 ++++++++++++++++++++++++++++ docs/strutil.md | 130 +++++++++++++++++++++- docs/strutil_zh-CN.md | 130 ++++++++++++++++++++++ random/random.go | 249 ++++++++++++++++-------------------------- random/random_test.go | 90 +++++++++++++++ strutil/string.go | 2 - 7 files changed, 771 insertions(+), 160 deletions(-) diff --git a/docs/random.md b/docs/random.md index 10e484a..800f5f4 100644 --- a/docs/random.md +++ b/docs/random.md @@ -30,7 +30,13 @@ import ( - [RandNumeral](#RandNumeral) - [RandNumeralOrLetter](#RandNumeralOrLetter) - [UUIdV4](#UUIdV4) +- [RandFloat](#RandFloat) +- [RandFloats](#RandFloats) - [RandUniqueIntSlice](#RandUniqueIntSlice) +- [RandIntSlice](#RandIntSlice) +- [RandStringSlice](#RandStringSlice) +- [RandBool](#RandBool) +- [RandBoolSlice](#RandBoolSlice)
@@ -247,6 +253,58 @@ func main() { } ``` +### RandFloat + +

Generate a random float64 number between [min, max) with specific precision.

+ +Signature: + +```go +func RandFloat(min, max float64, precision int) float64 +``` + +Example:[Run](https://go.dev/play/p/zbD_tuobJtr) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + floatNumber := random.RandFloat(1.0, 5.0, 2) + fmt.Println(floatNumber) //2.14 (random number) +} +``` + +### RandFloats + +

Generate a slice of random float64 numbers of length n that do not repeat. Number range in [min, max)

+ +Signature: + +```go +func RandFloats(length int, min, max float64, precision int) []float64 +``` + +Example:[Run](https://go.dev/play/p/I3yndUQ-rhh) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + floatNumbers := random.RandFloats(5, 1.0, 5.0, 2) + fmt.Println(floatNumbers) //[3.42 3.99 1.3 2.38 4.23] (random) +} +``` + ### RandUniqueIntSlice

Generate a slice of random int of length n that do not repeat.

@@ -272,3 +330,110 @@ func main() { fmt.Println(result) //[0 4 7 1 5] (random) } ``` + +### RandIntSlice + +

Generate a slice of random int. Number range in [min, max)

+ +Signature: + +```go +func RandIntSlice(length, min, max int) []int +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandIntSlice(5, 0, 10) + fmt.Println(result) //[1 4 7 1 5] (random) +} +``` + +### RandStringSlice + +

Generate a slice of random string of length strLen based on charset. chartset should be one of the following: random.Numeral, random.LowwerLetters, random.UpperLetters random.Letters, random.SymbolChars, random.AllChars. or a combination of them.

+ +Signature: + +```go +func RandStringSlice(charset string, sliceLen, strLen int) []string +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + strs := random.RandStringSlice(random.Letters, 4, 6) + fmt.Println(strs) + + // output random string slice like below: + //[CooSMq RUFjDz FAeMPf heRyGv] +} +``` + +### RandBool + +

Generate a random boolean value (true or false).

+ +Signature: + +```go +func RandBool() bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandBool() + fmt.Println(result) // true or false (random) +} +``` + +### RandBoolSlice + +

Generates a random boolean slice of specified length.

+ +Signature: + +```go +func RandBoolSlice(length int) []bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandBoolSlice(2) + fmt.Println(result) // [true false] (random) +} +``` \ No newline at end of file diff --git a/docs/random_zh-CN.md b/docs/random_zh-CN.md index 645ff48..c04b20e 100644 --- a/docs/random_zh-CN.md +++ b/docs/random_zh-CN.md @@ -30,7 +30,13 @@ import ( - [RandNumeral](#RandNumeral) - [RandNumeralOrLetter](#RandNumeralOrLetter) - [UUIdV4](#UUIdV4) +- [RandFloat](#RandFloat) +- [RandFloats](#RandFloats) - [RandUniqueIntSlice](#RandUniqueIntSlice) +- [RandIntSlice](#RandIntSlice) +- [RandStringSlice](#RandStringSlice) +- [RandBool](#RandBool) +- [RandBoolSlice](#RandBoolSlice)
@@ -247,6 +253,58 @@ func main() { } ``` +### RandFloat + +

Generate a random float64 number between [min, max) with specific precision.

+ +Signature: + +```go +func RandFloat(min, max float64, precision int) float64 +``` + +Example:[Run](https://go.dev/play/p/zbD_tuobJtr) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + floatNumber := random.RandFloat(1.0, 5.0, 2) + fmt.Println(floatNumber) //2.14 (random number) +} +``` + +### RandFloats + +

Generate a slice of random float64 numbers of length n that do not repeat. Number range in [min, max)

+ +Signature: + +```go +func RandFloats(length int, min, max float64, precision int) []float64 +``` + +Example:[Run](https://go.dev/play/p/I3yndUQ-rhh) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + floatNumbers := random.RandFloats(5, 1.0, 5.0, 2) + fmt.Println(floatNumbers) //[3.42 3.99 1.3 2.38 4.23] (random) +} +``` + ### RandUniqueIntSlice

生成一个不重复的长度为n的随机int切片。

@@ -272,3 +330,110 @@ func main() { fmt.Println(result) //[0 4 7 1 5] (random) } ``` + +### RandIntSlice + +

生成一个特定长度的随机int切片,数值范围[min, max)。

+ +函数签名: + +```go +func RandIntSlice(length, min, max int) []int +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandIntSlice(5, 0, 10) + fmt.Println(result) //[1 2 7 1 5] (random) +} +``` + +### RandStringSlice + +

生成随机字符串slice. 字符串类型需要是以下几种或者它们的组合: random.Numeral, random.LowwerLetters, random.UpperLetters random.Letters, random.SymbolChars, random.AllChars。

+ +函数签名: + +```go +func RandStringSlice(charset string, sliceLen, strLen int) []string +``` + +实例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + strs := random.RandStringSlice(random.Letters, 4, 6) + fmt.Println(strs) + + // output random string slice like below: + //[CooSMq RUFjDz FAeMPf heRyGv] +} +``` + +### RandBool + +

生成随机bool值(true or false)。

+ +函数签名: + +```go +func RandBool() bool +``` + +实例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandBool() + fmt.Println(result) // true or false (random) +} +``` + +### RandBoolSlice + +

生成特定长度的随机bool slice。

+ +函数签名: + +```go +func RandBoolSlice(length int) []bool +``` + +实例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/random" +) + +func main() { + result := random.RandBoolSlice(2) + fmt.Println(result) // [true false] (random) +} +``` \ No newline at end of file diff --git a/docs/strutil.md b/docs/strutil.md index 741370c..1aa6ce4 100644 --- a/docs/strutil.md +++ b/docs/strutil.md @@ -60,6 +60,10 @@ import ( - [RemoveWhiteSpace](#RemoveWhiteSpace) - [SubInBetween](#SubInBetween) - [HammingDistance](#HammingDistance) +- [Concat](#Concat) +- [Ellipsis](#Ellipsis) +- [Shuffle](#Shuffle) +- [Rotate](#Rotate)
@@ -1340,4 +1344,128 @@ func main() { // 0 // 1 } -``` \ No newline at end of file +``` + +### Concat + +

Concatenates strings. length is the length of the concatenated string. If unsure, pass 0 or a negative number.

+ +Signature: + +```go +func Concat(length int, str ...string) string +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.Concat(12, "Hello", " ", "World", "!") + result2 := strutil.Concat(11, "Go", " ", "Language") + result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away") + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // Hello World! + // Go Language + // An apple a day,keeps the doctor away +} +``` + +### Ellipsis + +

Truncates a string to a specified length and appends an ellipsis.

+ +Signature: + +```go +func Ellipsis(str string, length int) string +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.Ellipsis("hello world", 5) + result2 := strutil.Ellipsis("你好,世界!", 2) + result3 := strutil.Ellipsis("😀😃😄😁😆", 3) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // hello... + // 你好... + // 😀😃😄... +} +``` + +### Shuffle + +

Shuffle the order of characters of given string.

+ +Signature: + +```go +func Shuffle(str string) string +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result := strutil.Shuffle("hello") + fmt.Println(result) //olelh (random order) +} +``` + +### Rotate + +

Rotates the string by the specified number of characters.

+ +Signature: + +```go +func Rotate(str string, shift int) string +``` + +Example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := Rotate("Hello", 0) + result2 := Rotate("Hello", 1) + result3 := Rotate("Hello", 2) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // Hello + // oHell + // loHel +} \ No newline at end of file diff --git a/docs/strutil_zh-CN.md b/docs/strutil_zh-CN.md index 2f89198..71f9910 100644 --- a/docs/strutil_zh-CN.md +++ b/docs/strutil_zh-CN.md @@ -60,6 +60,10 @@ import ( - [RemoveWhiteSpace](#RemoveWhiteSpace) - [SubInBetween](#SubInBetween) - [HammingDistance](#HammingDistance) +- [Concat](#Concat) +- [Ellipsis](#Ellipsis) +- [Shuffle](#Shuffle) +- [Rotate](#Rotate)
@@ -1373,4 +1377,130 @@ func main() { // 0 // 1 } +``` + +### Concat + +

拼接字符串。length是拼接后字符串的长度,如果不确定则传0或负数。

+ +函数签名: + +```go +func Concat(length int, str ...string) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + + result1 := strutil.Concat(12, "Hello", " ", "World", "!") + result2 := strutil.Concat(11, "Go", " ", "Language") + result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away") + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // Hello World! + // Go Language + // An apple a day,keeps the doctor away +} +``` + +### Ellipsis + +

将字符串截断到指定长度,并在末尾添加省略号。

+ +函数签名: + +```go +func Ellipsis(str string, length int) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := strutil.Ellipsis("hello world", 5) + result2 := strutil.Ellipsis("你好,世界!", 2) + result3 := strutil.Ellipsis("😀😃😄😁😆", 3) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // hello... + // 你好... + // 😀😃😄... +} +``` + +### Shuffle + +

打乱给定字符串中的字符顺序。

+ +函数签名: + +```go +func Shuffle(str string) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result := strutil.Shuffle("hello") + fmt.Println(result) //olelh (random order) +} +``` + +### Rotate + +

按指定的字符数旋转字符串。

+ +函数签名: + +```go +func Rotate(str string, shift int) string +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + result1 := Rotate("Hello", 0) + result2 := Rotate("Hello", 1) + result3 := Rotate("Hello", 2) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + + // Output: + // Hello + // oHell + // loHel +} ``` \ No newline at end of file diff --git a/random/random.go b/random/random.go index b082d0b..117a8a2 100644 --- a/random/random.go +++ b/random/random.go @@ -31,6 +31,25 @@ func init() { rand.Seed(time.Now().UnixNano()) } +// RandBool generates a random boolean value (true or false). +func RandBool() bool { + return rand.Intn(2) == 1 +} + +// RandBoolSlice generates a random boolean slice of specified length. +func RandBoolSlice(length int) []bool { + if length <= 0 { + return []bool{} + } + + result := make([]bool, length) + for i := range result { + result[i] = RandBool() + } + + return result +} + // RandInt generate random int between [min, max). func RandInt(min, max int) int { if min == max { @@ -44,6 +63,45 @@ func RandInt(min, max int) int { return rand.Intn(max-min) + min } +// RandIntSlice generates a slice of random integers. +// The generated integers are between min and max (exclusive). +func RandIntSlice(length, min, max int) []int { + if length <= 0 || min > max { + return []int{} + } + + result := make([]int, length) + for i := range result { + result[i] = RandInt(min, max) + } + + return result +} + +// RandUniqueIntSlice generate a slice of random int of length n that do not repeat. +func RandUniqueIntSlice(n, min, max int) []int { + if min > max { + return []int{} + } + if n > max-min { + n = max - min + } + + nums := make([]int, n) + used := make(map[int]struct{}, n) + for i := 0; i < n; { + r := RandInt(min, max) + if _, use := used[r]; use { + continue + } + used[r] = struct{}{} + nums[i] = r + i++ + } + + return nums +} + // RandFloat generate random float64 number between [min, max) with specific precision. func RandFloat(min, max float64, precision int) float64 { if min == max { @@ -59,6 +117,23 @@ func RandFloat(min, max float64, precision int) float64 { return mathutil.RoundToFloat(n, precision) } +// RandFloats generate a slice of random float64 numbers of length n that do not repeat. +func RandFloats(n int, min, max float64, precision int) []float64 { + nums := make([]float64, n) + used := make(map[float64]struct{}, n) + for i := 0; i < n; { + r := RandFloat(min, max, precision) + if _, use := used[r]; use { + continue + } + used[r] = struct{}{} + nums[i] = r + i++ + } + + return nums +} + // RandBytes generate random byte slice. // Play: https://go.dev/play/p/EkiLESeXf8d func RandBytes(length int) []byte { @@ -79,6 +154,23 @@ func RandString(length int) string { return random(Letters, length) } +// RandString generate a slice of random string of length strLen based on charset. +// chartset should be one of the following: random.Numeral, random.LowwerLetters, random.UpperLetters +// random.Letters, random.SymbolChars, random.AllChars. or a combination of them. +func RandStringSlice(charset string, sliceLen, strLen int) []string { + if sliceLen <= 0 || strLen <= 0 { + return []string{} + } + + result := make([]string, sliceLen) + + for i := range result { + result[i] = random(charset, strLen) + } + + return result +} + // RandUpper generate a random upper case string of specified length. func RandUpper(length int) string { return random(UpperLetters, length) @@ -176,160 +268,3 @@ func UUIdV4() (string, error) { return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil } - -// RandUniqueIntSlice generate a slice of random int of length n that do not repeat. -func RandUniqueIntSlice(n, min, max int) []int { - if min > max { - return []int{} - } - if n > max-min { - n = max - min - } - - nums := make([]int, n) - used := make(map[int]struct{}, n) - for i := 0; i < n; { - r := RandInt(min, max) - if _, use := used[r]; use { - continue - } - used[r] = struct{}{} - nums[i] = r - i++ - } - - return nums -} - -// RandFloats generate a slice of random float64 numbers of length n that do not repeat. -func RandFloats(n int, min, max float64, precision int) []float64 { - nums := make([]float64, n) - used := make(map[float64]struct{}, n) - for i := 0; i < n; { - r := RandFloat(min, max, precision) - if _, use := used[r]; use { - continue - } - used[r] = struct{}{} - nums[i] = r - i++ - } - - return nums -} - -// const ( -// NUMERAL = "0123456789" -// LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz" -// UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -// LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -// ) - -// var rn = rand.NewSource(time.Now().UnixNano()) - -// func init() { -// rand.Seed(time.Now().UnixNano()) -// } - -// // RandInt generate random int between min and max, maybe min, not be max -// func RandInt(min, max int) int { -// if min == max { -// return min -// } - -// if max < min { -// min, max = max, min -// } - -// return rand.Intn(max-min) + min -// } - -// // RandBytes generate random byte slice -// func RandBytes(length int) []byte { -// if length < 1 { -// return []byte{} -// } -// b := make([]byte, length) - -// if _, err := io.ReadFull(crand.Reader, b); err != nil { -// return nil -// } -// return b -// } - -// // RandString generate random string -// func RandString(length int) string { -// return random(LETTERS, length) -// } - -// // RandUpper generate a random upper case string -// func RandUpper(length int) string { -// return random(UPPER_LETTERS, length) -// } - -// // RandLower generate a random lower case string -// func RandLower(length int) string { -// return random(LOWER_LETTERS, length) -// } - -// // RandNumeral generate a random numeral string -// func RandNumeral(length int) string { -// return random(NUMERAL, length) -// } - -// // RandNumeralOrLetter generate a random numeral or letter string -// func RandNumeralOrLetter(length int) string { -// return random(NUMERAL+LETTERS, length) -// } - -// // random generate a random string based on given string range -// func random(s string, length int) string { -// b := make([]byte, length) - -// // fix: https://github.com/duke-git/lancet/issues/75 -// // r := rand.New(rand.NewSource(time.Now().UnixNano())) - -// for i := range b { -// b[i] = s[rand.Int63()%int64(len(s))] -// } -// return string(b) -// } - -// // UUIdV4 generate a random UUID of version 4 according to RFC 4122 -// func UUIdV4() (string, error) { -// uuid := make([]byte, 16) - -// n, err := io.ReadFull(crand.Reader, uuid) -// if n != len(uuid) || err != nil { -// return "", err -// } - -// uuid[8] = uuid[8]&^0xc0 | 0x80 -// uuid[6] = uuid[6]&^0xf0 | 0x40 - -// return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil -// } - -// // RandUniqueIntSlice generate a slice of random int of length n that do not repeat. -// func RandUniqueIntSlice(n, min, max int) []int { -// if min > max { -// return []int{} -// } -// if n > max-min { -// n = max - min -// } - -// nums := make([]int, n) -// used := make(map[int]struct{}, n) -// for i := 0; i < n; { -// r := RandInt(min, max) -// if _, use := used[r]; use { -// continue -// } -// used[r] = struct{}{} -// nums[i] = r -// i++ -// } - -// return nums -// } diff --git a/random/random_test.go b/random/random_test.go index 624077b..3b2e096 100644 --- a/random/random_test.go +++ b/random/random_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/duke-git/lancet/internal" + "github.com/duke-git/lancet/validator" ) func TestRandString(t *testing.T) { @@ -138,3 +139,92 @@ func hasDuplicate(arr []int) bool { } return false } + +func TestRandBool(t *testing.T) { + t.Parallel() + assert := internal.NewAssert(t, "TestRandBool") + + result := RandBool() + assert.Equal(true, result == true || result == false) +} + +func TestRandBoolSlice(t *testing.T) { + t.Parallel() + assert := internal.NewAssert(t, "TestRandBoolSlice") + + t.Run("empty slice", func(t *testing.T) { + bools := RandBoolSlice(-1) + assert.Equal([]bool{}, bools) + + bools = RandBoolSlice(0) + assert.Equal([]bool{}, bools) + }) + + t.Run("random bool slice", func(t *testing.T) { + bools := RandBoolSlice(6) + assert.Equal(6, len(bools)) + + for _, b := range bools { + assert.Equal(true, b == true || b == false) + } + }) +} + +func TestRandStringSlice(t *testing.T) { + t.Parallel() + assert := internal.NewAssert(t, "TestRandStringSlice") + + t.Run("empty slice", func(t *testing.T) { + strs := RandStringSlice(Letters, -1, -1) + assert.Equal([]string{}, strs) + + strs = RandStringSlice(Letters, 0, 0) + assert.Equal([]string{}, strs) + + strs = RandStringSlice(Letters, -1, 0) + assert.Equal([]string{}, strs) + + strs = RandStringSlice(Letters, 0, -1) + assert.Equal([]string{}, strs) + + strs = RandStringSlice(Letters, 1, 0) + assert.Equal([]string{}, strs) + + strs = RandStringSlice(Letters, 0, 1) + assert.Equal([]string{}, strs) + }) + + t.Run("random string slice", func(t *testing.T) { + strs := RandStringSlice(Letters, 4, 6) + assert.Equal(4, len(strs)) + + for _, s := range strs { + assert.Equal(true, validator.IsAlpha(s)) + assert.Equal(6, len(s)) + } + }) +} + +func TestRandIntSlice(t *testing.T) { + t.Parallel() + assert := internal.NewAssert(t, "TestRandIntSlice") + + t.Run("empty slice", func(t *testing.T) { + numbers := RandIntSlice(-1, 1, 5) + assert.Equal([]int{}, numbers) + + numbers = RandIntSlice(0, 1, 5) + assert.Equal([]int{}, numbers) + + numbers = RandIntSlice(3, 5, 1) + assert.Equal([]int{}, numbers) + }) + + t.Run("random int slice", func(t *testing.T) { + numbers := RandIntSlice(5, 1, 1) + assert.Equal([]int{1, 1, 1, 1, 1}, numbers) + + numbers = RandIntSlice(5, 1, 5) + assert.Equal(5, len(numbers)) + }) +} diff --git a/strutil/string.go b/strutil/string.go index 31289d1..6e4e587 100644 --- a/strutil/string.go +++ b/strutil/string.go @@ -569,8 +569,6 @@ func HammingDistance(a, b string) (int, error) { // Concat uses the strings.Builder to concatenate the input strings. // - `length` is the expected length of the concatenated string. // - if you are unsure about the length of the string to be concatenated, please pass 0 or a negative number. -// -// Play: todo func Concat(length int, str ...string) string { if len(str) == 0 { return ""