From 79c590957c640dbcb862352ff7c92872e350138f Mon Sep 17 00:00:00 2001 From: what-00 Date: Sat, 15 Apr 2023 00:04:50 +0800 Subject: [PATCH] first commit --- README.md | 1 + base62.go | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ base62_test.go | 13 ++++++ go.mod | 7 +++ go.sum | 4 ++ 5 files changed, 146 insertions(+) create mode 100644 README.md create mode 100644 base62.go create mode 100644 base62_test.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/README.md b/README.md new file mode 100644 index 0000000..995862d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +#go-base62 diff --git a/base62.go b/base62.go new file mode 100644 index 0000000..ec87997 --- /dev/null +++ b/base62.go @@ -0,0 +1,121 @@ +package base62 + +import ( + "bytes" + "errors" + + "github.com/samber/lo" +) + +type Base62 struct { + characters []byte // base62 编码规则 + charactersMap map[byte]int // base62 编码规则 +} + +var base62 *Base62 + +func init() { + base62 = &Base62{} + base62.SetCharacters([]byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) +} + +func GetInstance() *Base62 { + return base62 +} + +func (base62 *Base62) SetCharacters(characters []byte) (*Base62, error) { + characters = lo.FindUniques(characters) + charactersMap := make(map[byte]int) + + if len(characters) != 62 { + return nil, errors.New("Invalid characters") + } + + for i, v := range characters { + charactersMap[v] = i + } + + base62.characters = characters + base62.charactersMap = charactersMap + + return base62, nil +} + +// Encode function receives a byte slice and encodes it to a string using the alphabet provided +func (e *Base62) Encode(source []byte) string { + if len(source) == 0 { + return "" + } + + digits := []int{0} + + for i := 0; i < len(source); i++ { + carry := int(source[i]) + + for j := 0; j < len(digits); j++ { + carry += digits[j] << 8 + digits[j] = carry % 62 + carry = carry / 62 + } + + for carry > 0 { + digits = append(digits, carry%62) + carry = carry / 62 + } + } + + var res bytes.Buffer + + for k := 0; source[k] == 0 && k < len(source)-1; k++ { + res.WriteByte(base62.characters[0]) + } + + for q := len(digits) - 1; q >= 0; q-- { + res.WriteByte(base62.characters[digits[q]]) + } + + return res.String() +} + +// Decode function decodes a string previously obtained from Encode, using the same alphabet and returns a byte slice +// In case the input is not valid an arror will be returned +func (base62 *Base62) Decode(source string) ([]byte, error) { + if len(source) == 0 { + return []byte{}, nil + } + + runes := []byte(source) + + bytes := []byte{0} + for i := 0; i < len(runes); i++ { + value, ok := base62.charactersMap[runes[i]] + + if !ok { + return nil, errors.New("Non Base Character") + } + + carry := int(value) + + for j := 0; j < len(bytes); j++ { + carry += int(bytes[j]) * 62 + bytes[j] = byte(carry & 0xff) + carry >>= 8 + } + + for carry > 0 { + bytes = append(bytes, byte(carry&0xff)) + carry >>= 8 + } + } + + for k := 0; runes[k] == base62.characters[0] && k < len(runes)-1; k++ { + bytes = append(bytes, 0) + } + + // Reverse bytes + for i, j := 0, len(bytes)-1; i < j; i, j = i+1, j-1 { + bytes[i], bytes[j] = bytes[j], bytes[i] + } + + return bytes, nil +} diff --git a/base62_test.go b/base62_test.go new file mode 100644 index 0000000..6cc04c3 --- /dev/null +++ b/base62_test.go @@ -0,0 +1,13 @@ +package base62 + +import ( + "testing" +) + +func TestEncode(t *testing.T) { + e := GetInstance().Encode([]byte("问问哇啊啊")) + t.Log(e) + + d, err := GetInstance().Decode(e) + t.Log(string(d), err) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d118a3f --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module git.fsdpf.net/go/base62 + +go 1.18 + +require github.com/samber/lo v1.38.1 + +require golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7a26b7e --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=