Golang中如何缩短UUID字符串

Golang中如何缩短UUID字符串 大家好! 我正在寻找一种替代方案,以使 UUID.String() 的字符串表示更短。

当前长度是36个字符,例如:964238a0-8188-465f-8347-657819bf789a。 使用 ascii85 编码后长度为20,例如:Q9mR(JVZd&K1BKt)8CEb

有什么想法吗?

Go Playground 上的示例(链接)

package main

import (
    "encoding/ascii85"
    "fmt"

    "github.com/google/uuid"
)

func main() {
    originalUUID := uuid.New()
    originalSlice, _ := originalUUID.MarshalBinary()
    enc := make([]byte, ascii85.MaxEncodedLen(len(originalUUID)))
    ascii85.Encode(enc, originalSlice)
    newStringID := originalUUID.String()
    
    fmt.Printf("uuid    - len: %d, string: '%s'\n", len(newStringID), newStringID)
    fmt.Printf("ascii85 - len: %d, string: '%s'\n", len(enc), string(enc))

    // Just for testing:
    dst := make([]byte, 16)
    ascii85.Decode(dst, enc, true)
    uuidDecoded, _ := uuid.FromBytes(dst)
    fmt.Printf("decoded - len: %d, string: '%s'\n", len(uuidDecoded.String()), uuidDecoded.String())
}

输出:

uuid - len: 36, string: ‘964238a0-8188-465f-8347-657819bf789a’ ascii85 - len: 20, string: ‘Q9mR(JVZd&K1BKt)8CEb’ decoded - len: 36, string: ‘964238a0-8188-465f-8347-657819bf789a’


更多关于Golang中如何缩短UUID字符串的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

我需要以字符串形式将其发送给第三方。

更多关于Golang中如何缩短UUID字符串的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


为了你自己好,请以规范化的表示形式发送给他们。

从长远来看,这会为你省去很多麻烦。

为什么不直接将其存储为 BLOB/BINARY/BYTEA 或您的数据库管理系统用于存储二进制数据的任何数据类型呢?为什么要在数据库中将其转换为字符串?

你好 @GonzaSaya

我虽然不是UUID专家,但在我看来,ascii85已经是一种非常紧凑的格式了,因为它使用了大量字符进行编码。

要获得更短的ID,我会尝试以下方法之一:

  1. 使用二进制压缩。如果ID不需要是可打印的,这种方法很合适。

  2. 使用另一种唯一ID格式。UUID旨在实现全局唯一性。也就是说,在世界任何地方生成相同UUID的可能性应该非常低。如果你可以接受一个仅在数据库、服务器集群或公司内部等范围内唯一的ID,那么除了UUID之外,还有其他算法可以生成更短的唯一ID。

可以使用Base32或Base64编码来进一步缩短UUID的字符串表示。以下是几种实现方案:

1. Base64编码(22字符)

package main

import (
    "encoding/base64"
    "fmt"
    "github.com/google/uuid"
)

func main() {
    id := uuid.New()
    
    // 标准Base64
    b64 := base64.RawURLEncoding.EncodeToString(id[:])
    fmt.Printf("Base64 - len: %d, string: '%s'\n", len(b64), b64)
    
    // 解码验证
    decoded, _ := base64.RawURLEncoding.DecodeString(b64)
    uuidDecoded, _ := uuid.FromBytes(decoded)
    fmt.Printf("Decoded: %s\n", uuidDecoded)
}

2. Base32编码(26字符)

package main

import (
    "encoding/base32"
    "fmt"
    "github.com/google/uuid"
    "strings"
)

func main() {
    id := uuid.New()
    
    // Base32编码(去掉填充字符)
    b32 := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(id[:])
    fmt.Printf("Base32 - len: %d, string: '%s'\n", len(b32), b32)
    
    // 解码验证
    decoded, _ := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(b32)
    uuidDecoded, _ := uuid.FromBytes(decoded)
    fmt.Printf("Decoded: %s\n", uuidDecoded)
}

3. Base58编码(约22字符)

package main

import (
    "fmt"
    "github.com/google/uuid"
    "github.com/btcsuite/btcutil/base58"
)

func main() {
    id := uuid.New()
    
    // Base58编码(比特币风格)
    b58 := base58.Encode(id[:])
    fmt.Printf("Base58 - len: %d, string: '%s'\n", len(b58), b58)
    
    // 解码验证
    decoded := base58.Decode(b58)
    uuidDecoded, _ := uuid.FromBytes(decoded)
    fmt.Printf("Decoded: %s\n", uuidDecoded)
}

4. 十六进制压缩(32字符)

package main

import (
    "fmt"
    "github.com/google/uuid"
    "strings"
)

func main() {
    id := uuid.New()
    
    // 去掉连字符的十六进制
    hexStr := strings.ReplaceAll(id.String(), "-", "")
    fmt.Printf("Hex - len: %d, string: '%s'\n", len(hexStr), hexStr)
    
    // 解码验证
    uuidDecoded, _ := uuid.Parse(hexStr)
    fmt.Printf("Decoded: %s\n", uuidDecoded)
}

5. 自定义Base62编码(约22字符)

package main

import (
    "fmt"
    "github.com/google/uuid"
    "math/big"
)

const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

func encodeBase62(data []byte) string {
    n := new(big.Int).SetBytes(data)
    result := ""
    zero := big.NewInt(0)
    base := big.NewInt(62)
    
    for n.Cmp(zero) > 0 {
        mod := new(big.Int)
        n.DivMod(n, base, mod)
        result = string(base62Chars[mod.Int64()]) + result
    }
    
    return result
}

func main() {
    id := uuid.New()
    
    base62 := encodeBase62(id[:])
    fmt.Printf("Base62 - len: %d, string: '%s'\n", len(base62), base62)
}

性能对比示例

package main

import (
    "encoding/base32"
    "encoding/base64"
    "fmt"
    "github.com/google/uuid"
    "strings"
    "time"
)

func main() {
    id := uuid.New()
    
    // 各种编码方式
    methods := []struct {
        name string
        fn   func(uuid.UUID) string
    }{
        {"Original", func(u uuid.UUID) string { return u.String() }},
        {"Hex", func(u uuid.UUID) string { return strings.ReplaceAll(u.String(), "-", "") }},
        {"Base64", func(u uuid.UUID) string { 
            return base64.RawURLEncoding.EncodeToString(u[:]) 
        }},
        {"Base32", func(u uuid.UUID) string { 
            return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(u[:]) 
        }},
    }
    
    for _, method := range methods {
        start := time.Now()
        encoded := method.fn(id)
        elapsed := time.Since(start)
        
        fmt.Printf("%-10s len: %2d, time: %v\n", 
            method.name+":", len(encoded), elapsed)
    }
}

输出示例:

Original:  len: 36, time: 1.042µs
Hex:       len: 32, time: 1.125µs
Base64:    len: 22, time: 1.292µs
Base32:    len: 26, time: 1.375µs

Base64.RawURLEncoding是最佳选择,它生成22个字符的URL安全字符串,没有填充字符,且Go标准库原生支持。

回到顶部