mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
2 Commits
38920e3be6
...
4c21fe700c
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c21fe700c | |||
| b7370e8ef8 |
+62
-14
@@ -8,20 +8,25 @@ import (
|
|||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/mathutil"
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Numeral = "0123456789"
|
MaximumCapacity = 1 << 31
|
||||||
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
Numeral = "0123456789"
|
||||||
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||||
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
|
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var rn = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
@@ -108,18 +113,61 @@ func RandSymbolChar(length int) string {
|
|||||||
return random(SymbolChars, length)
|
return random(SymbolChars, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nearestPowerOfTwo 返回一个大于等于cap的最近的2的整数次幂,参考java8的hashmap的tableSizeFor函数
|
||||||
|
func nearestPowerOfTwo(cap int) int {
|
||||||
|
n := cap - 1
|
||||||
|
n |= n >> 1
|
||||||
|
n |= n >> 2
|
||||||
|
n |= n >> 4
|
||||||
|
n |= n >> 8
|
||||||
|
n |= n >> 16
|
||||||
|
if n < 0 {
|
||||||
|
return 1
|
||||||
|
} else if n >= MaximumCapacity {
|
||||||
|
return MaximumCapacity
|
||||||
|
}
|
||||||
|
return n + 1
|
||||||
|
}
|
||||||
|
|
||||||
// random generate a random string based on given string range.
|
// random generate a random string based on given string range.
|
||||||
func random(s string, length int) string {
|
func random(s string, length int) string {
|
||||||
b := make([]byte, length)
|
// 仿照strings.Builder
|
||||||
|
// 创建一个长度为 length 的字节切片
|
||||||
// fix: https://github.com/duke-git/lancet/issues/75
|
bytes := make([]byte, length)
|
||||||
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
strLength := len(s)
|
||||||
|
if strLength <= 0 {
|
||||||
for i := range b {
|
return ""
|
||||||
b[i] = s[rand.Int63()%int64(len(s))]
|
} else if strLength == 1 {
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
bytes[i] = s[0]
|
||||||
|
}
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes))
|
||||||
}
|
}
|
||||||
|
// s的字符需要使用多少个比特位数才能表示完
|
||||||
return string(b)
|
// letterIdBits := int(math.Ceil(math.Log2(strLength))),下面比上面的代码快
|
||||||
|
letterIdBits := int(math.Log2(float64(nearestPowerOfTwo(strLength))))
|
||||||
|
// 最大的字母id掩码
|
||||||
|
var letterIdMask int64 = 1<<letterIdBits - 1
|
||||||
|
// 可用次数的最大值
|
||||||
|
letterIdMax := 63 / letterIdBits
|
||||||
|
// 循环生成随机字符串
|
||||||
|
for i, cache, remain := length-1, rn.Int63(), letterIdMax; i >= 0; {
|
||||||
|
// 检查随机数生成器是否用尽所有随机数
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = rn.Int63(), letterIdMax
|
||||||
|
}
|
||||||
|
// 从可用字符的字符串中随机选择一个字符
|
||||||
|
if idx := int(cache & letterIdMask); idx < len(s) {
|
||||||
|
bytes[i] = s[idx]
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
// 右移比特位数,为下次选择字符做准备
|
||||||
|
cache >>= letterIdBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
// 仿照strings.Builder用unsafe包返回一个字符串,避免拷贝
|
||||||
|
// 将字节切片转换为字符串并返回
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122.
|
// UUIdV4 generate a random UUID of version 4 according to RFC 4122.
|
||||||
|
|||||||
+1
-5
@@ -4,7 +4,6 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
@@ -380,10 +379,7 @@ func RemoveNonPrintable(str string) string {
|
|||||||
// StringToBytes converts a string to byte slice without a memory allocation.
|
// StringToBytes converts a string to byte slice without a memory allocation.
|
||||||
// Play: https://go.dev/play/p/7OyFBrf9AxA
|
// Play: https://go.dev/play/p/7OyFBrf9AxA
|
||||||
func StringToBytes(str string) (b []byte) {
|
func StringToBytes(str string) (b []byte) {
|
||||||
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
|
return *(*[]byte)(unsafe.Pointer(&str))
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
||||||
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BytesToString converts a byte slice to string without a memory allocation.
|
// BytesToString converts a byte slice to string without a memory allocation.
|
||||||
|
|||||||
Reference in New Issue
Block a user