Skip to content

Commit

Permalink
👔 up: strutil - update some string util functions
Browse files Browse the repository at this point in the history
- add new func: DateSN, DateSNV2
- remove some encode func to new pgk encodes
  • Loading branch information
inhere committed Sep 16, 2023
1 parent bd472a7 commit 9723aea
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 131 deletions.
9 changes: 9 additions & 0 deletions strutil/check.go
Expand Up @@ -60,6 +60,9 @@ func ContainsByte(s string, c byte) bool {
return strings.IndexByte(s, c) >= 0
}

// InArray alias of HasOneSub()
var InArray = HasOneSub

// ContainsOne substr(s) in the given string. alias of HasOneSub()
func ContainsOne(s string, subs []string) bool { return HasOneSub(s, subs) }

Expand All @@ -86,6 +89,9 @@ func HasAllSubs(s string, subs []string) bool {
return true
}

// StartsWithAny alias of the HasOnePrefix
var StartsWithAny = HasOneSuffix

// IsStartsOf alias of the HasOnePrefix
func IsStartsOf(s string, prefixes []string) bool {
return HasOnePrefix(s, prefixes)
Expand All @@ -101,6 +107,9 @@ func HasOnePrefix(s string, prefixes []string) bool {
return false
}

// StartsWith alias func for HasPrefix
var StartsWith = strings.HasPrefix

// HasPrefix substr in the given string.
func HasPrefix(s string, prefix string) bool { return strings.HasPrefix(s, prefix) }

Expand Down
4 changes: 4 additions & 0 deletions strutil/check_test.go
Expand Up @@ -74,8 +74,12 @@ func TestIsStartOf(t *testing.T) {
assert.Eq(t, item.want, strutil.IsStartOf(item.give, item.sub))
}

assert.True(t, strutil.StartsWith("abc", "a"))

assert.True(t, strutil.IsStartsOf("abc", []string{"a", "b"}))
assert.True(t, strutil.StartsWithAny("abc", []string{"a", "c"}))
assert.False(t, strutil.IsStartsOf("abc", []string{"d", "e"}))
assert.False(t, strutil.StartsWithAny("abc", []string{"d", "e"}))
}

func TestIsEndOf(t *testing.T) {
Expand Down
1 change: 0 additions & 1 deletion strutil/convbase.go
Expand Up @@ -40,7 +40,6 @@ func BaseConv(src string, from, to int) string {
if to > 64 || to < 2 {
return ""
}

return BaseConvByTpl(src, Base64Chars[:from], Base64Chars[:to])
}

Expand Down
44 changes: 0 additions & 44 deletions strutil/encode.go
Expand Up @@ -141,47 +141,3 @@ func B64DecodeBytes(str []byte) []byte {
n, _ := B64Std.Decode(dbuf, str)
return dbuf[:n]
}

// BaseEncoder interface
type BaseEncoder interface {
Encode(dst []byte, src []byte)
EncodeToString(src []byte) string
Decode(dst []byte, src []byte) (n int, err error)
DecodeString(s string) ([]byte, error)
}

// BaseType for base encoding
type BaseType uint8

// types for base encoding
const (
BaseTypeStd BaseType = iota
BaseTypeHex
BaseTypeURL
BaseTypeRawStd
BaseTypeRawURL
)

// Encoding instance. base: 32 or 64, typ: 0 - 4
func Encoding(base int, typ BaseType) BaseEncoder {
if base == 32 {
switch typ {
case BaseTypeHex:
return base32.HexEncoding
default:
return base32.StdEncoding
}
}

// base 64
switch typ {
case BaseTypeURL:
return base64.URLEncoding
case BaseTypeRawURL:
return base64.RawURLEncoding
case BaseTypeRawStd:
return base64.RawStdEncoding
default:
return base64.StdEncoding
}
}
125 changes: 125 additions & 0 deletions strutil/gensn.go
@@ -0,0 +1,125 @@
package strutil

import (
"hash/crc32"
"math/rand"
"os"
"strconv"
"time"

"github.com/gookit/goutil/basefn"
"github.com/gookit/goutil/mathutil"
)

// global id:
//
// https://github.com/rs/xid
// https://github.com/satori/go.uuid
var (
DefMinInt = 1000
DefMaxInt = 9999
)

// MicroTimeID generate.
// - return like: 16074145697981929446(len: 20)
//
// Conv Base:
//
// mtId := MicroTimeID() // eg: 16935349145643425047 len: 20
// b16id := Base10Conv(mtId, 16) // eg: eb067252154a9d17 len: 16
// b32id := Base10Conv(mtId, 32) // eg: em1jia8akl78n len: 13
// b36id := Base10Conv(mtId, 36) // eg: 3ko088phiuoev len: 13
// b62id := Base10Conv(mtId, 62) // eg: kb24SKgsQ9V len: 11
func MicroTimeID() string {
return MTimeBaseID(10)
}

// MicroTimeHexID micro time hex id generate.
//
// return like: 5b5f0588af1761ad3(len: 16-17)
func MicroTimeHexID() string { return MTimeHexID() }

// MTimeHexID micro time hex id generate.
//
// return like: 5b5f0588af1761ad3(len: 16-17)
func MTimeHexID() string {
return MTimeBaseID(16)
}

// MTimeBaseID micro time BASE id generate. toBase: 2 - 36
//
// Examples:
// - MTimeBaseID(16): 5b5f0588af1761ad3(len: 16-17)
// - MTimeBaseID(36): gorntzvsa73mo(len: 13)
func MTimeBaseID(toBase int) string {
ms := time.Now().UnixMicro()
ri := mathutil.RandomInt(DefMinInt, DefMaxInt)
return strconv.FormatInt(ms, toBase) + strconv.FormatInt(int64(ri), toBase)
}

// DatetimeNo generate. can use for order-no.
//
// - No prefix, return like: 2023041410484904074285478388(len: 28)
// - With prefix, return like: prefix2023041410484904074285478388(len: 28 + len(prefix))
func DatetimeNo(prefix string) string {
return DateSN(prefix)
}

// DateSN generate date serial number. PREFIX + yyyyMMddHHmmss + ext(微秒+随机数)
func DateSN(prefix string) string {
nt := time.Now()
pl := len(prefix)
bs := make([]byte, 0, 28+pl)
if pl > 0 {
bs = append(bs, prefix...)
}

// micro datetime
bs = nt.AppendFormat(bs, "20060102150405.000000")
bs[14+pl] = '0'

// host
name, err := os.Hostname()
if err != nil {
name = "default"
}
c32 := crc32.ChecksumIEEE([]byte(name)) // eg: 4006367001
bs = strconv.AppendUint(bs, uint64(c32%99), 10)

// rand 1000 - 9999
rs := rand.New(rand.NewSource(nt.UnixNano()))
bs = strconv.AppendInt(bs, 1000+rs.Int63n(8999), 10)

return string(bs)
}

// DateSNV2 generate date serial number.
// - 2 < extBase <= 36
// - return: PREFIX + yyyyMMddHHmmss + extBase(6bit micro + 5bit random number)
//
// Example:
// - prefix=P, extBase=16, return: P2023091414361354b4490(len=22)
// - prefix=P, extBase=36, return: P202309141436131gw3jg(len=21)
func DateSNV2(prefix string, extBase ...int) string {
pl := len(prefix)
bs := make([]byte, 0, 22+pl)
if pl > 0 {
bs = append(bs, prefix...)
}

// micro datetime
nt := time.Now()
bs = nt.AppendFormat(bs, "20060102150405.000000")
bs = bs[:14+pl] // prefix + yyyyMMddHHmmss
ext := bs[15+pl:] // 6bit micro + 5bit rand

// rand 10000 - 99999
rs := rand.New(rand.NewSource(nt.UnixNano()))
ext = strconv.AppendInt(ext, 10000+rs.Int63n(89999), 10)

base := basefn.FirstOr(extBase, 16)
// convert ext to base
bs = append(bs[:15+pl], strconv.FormatInt(SafeInt64(string(ext)), base)...)

return string(bs)
}
26 changes: 24 additions & 2 deletions strutil/id_test.go → strutil/gensn_test.go
Expand Up @@ -27,18 +27,40 @@ func TestMicroTimeID(t *testing.T) {
fmt.Println("b62id:", b62id, "len:", len(b62id))
}

func TestMicroTimeHexID(t *testing.T) {
func TestMicroTimeBaseID(t *testing.T) {
fmt.Println("Base 16:")
for i := 0; i < 10; i++ {
id := strutil.MicroTimeHexID()
fmt.Println(id, "len:", len(id))
assert.NotEmpty(t, id)
}

fmt.Println("Base 36:")
for i := 0; i < 10; i++ {
id := strutil.MTimeBaseID(36)
fmt.Println(id, "len:", len(id))
assert.NotEmpty(t, id)
}
}

func TestDatetimeNo(t *testing.T) {
func TestDateSN(t *testing.T) {
for i := 0; i < 10; i++ {
no := strutil.DatetimeNo("test")
fmt.Println(no, "len:", len(no))
assert.NotEmpty(t, no)
}
}

func TestDateSNV2(t *testing.T) {
for i := 0; i < 10; i++ {
no := strutil.DateSNV2("test")
fmt.Println(no, "len:", len(no))
assert.NotEmpty(t, no)
}

for i := 0; i < 10; i++ {
no := strutil.DateSNV2("test", 36)
fmt.Println(no, "len:", len(no))
assert.NotEmpty(t, no)
}
}
76 changes: 0 additions & 76 deletions strutil/id.go

This file was deleted.

0 comments on commit 9723aea

Please sign in to comment.