109 lines
2.3 KiB
Go
109 lines
2.3 KiB
Go
package base36
|
||
|
||
import (
|
||
"fmt"
|
||
"math/big"
|
||
"strings"
|
||
)
|
||
|
||
// Encode 将字节数据编码为Base36字符串(大写),使用=作为padding字符
|
||
func Encode(src []byte) string {
|
||
if len(src) == 0 {
|
||
return ""
|
||
}
|
||
|
||
// 将字节转换为big.Int
|
||
num := new(big.Int).SetBytes(src)
|
||
|
||
// 如果输入为全零字节,则直接返回"0"
|
||
if num.Cmp(big.NewInt(0)) == 0 {
|
||
return "0"
|
||
}
|
||
|
||
// 进行Base36编码
|
||
var result strings.Builder
|
||
base := big.NewInt(36)
|
||
zero := big.NewInt(0)
|
||
remainder := new(big.Int)
|
||
|
||
// 重复除以36,获取余数作为字符
|
||
for num.Cmp(zero) > 0 {
|
||
num.DivMod(num, base, remainder)
|
||
digit := remainder.Int64()
|
||
|
||
if digit < 10 {
|
||
result.WriteString(fmt.Sprintf("%d", digit))
|
||
} else {
|
||
result.WriteString(fmt.Sprintf("%c", 'A'+digit-10))
|
||
}
|
||
}
|
||
|
||
// 反转字符串,因为我们是从低位开始计算的
|
||
encoded := result.String()
|
||
runes := []rune(encoded)
|
||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||
runes[i], runes[j] = runes[j], runes[i]
|
||
}
|
||
|
||
return string(runes)
|
||
}
|
||
|
||
// Decode 将Base36字符串(可为任意大小写)解码为字节数组
|
||
func Decode(src string) ([]byte, error) {
|
||
if src == "" {
|
||
return []byte{}, nil
|
||
}
|
||
|
||
// 移除padding字符
|
||
src = strings.ReplaceAll(src, "=", "")
|
||
src = strings.ToUpper(src)
|
||
|
||
// 使用big.Int进行解码
|
||
num := big.NewInt(0)
|
||
base := big.NewInt(36)
|
||
|
||
for _, char := range src {
|
||
var digit int64
|
||
|
||
switch {
|
||
case char >= '0' && char <= '9':
|
||
digit = int64(char - '0')
|
||
case char >= 'A' && char <= 'Z':
|
||
digit = int64(char - 'A' + 10)
|
||
default:
|
||
return nil, fmt.Errorf("invalid character %c in base36 string", char)
|
||
}
|
||
|
||
num.Mul(num, base)
|
||
num.Add(num, big.NewInt(digit))
|
||
}
|
||
|
||
// 转换为字节数组
|
||
return num.Bytes(), nil
|
||
}
|
||
|
||
// EncodeToString 是Encode的别名,用于保持与标准库一致的命名
|
||
func EncodeToString(src []byte) string {
|
||
return Encode(src)
|
||
}
|
||
|
||
// DecodeString 是Decode的别名,用于保持与标准库一致的命名
|
||
func DecodeString(src string) ([]byte, error) {
|
||
return Decode(src)
|
||
}
|
||
|
||
// EncodeInt64 将int64转换为Base36字符串
|
||
func EncodeInt64(num int64) string {
|
||
return EncodeToString(big.NewInt(num).Bytes())
|
||
}
|
||
|
||
// DecodeToInt64 将Base36字符串解码为int64
|
||
func DecodeToInt64(src string) (int64, error) {
|
||
bytes, err := DecodeString(src)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
return new(big.Int).SetBytes(bytes).Int64(), nil
|
||
}
|