diff --git a/serialize/base36/base36.go b/serialize/base36/base36.go new file mode 100644 index 0000000..bf44fd0 --- /dev/null +++ b/serialize/base36/base36.go @@ -0,0 +1,108 @@ +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 +}