为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中将 UUID 输出为短字符串

在 Go 中将 UUID 输出为短字符串

Go
一只斗牛犬 2022-01-17 19:57:24
是否有内置方式或合理的标准包允许您将标准 UUID 转换为可以启用更短 URL 的短字符串?即利用更大范围的字符[A-Za-z0-9]来输出更短的字符串。我知道我们可以使用 base64 对字节进行编码,如下所示,但我想要创建一个看起来像“单词”的字符串,即 no+和/:id = base64.StdEncoding.EncodeToString(myUuid.Bytes())
查看完整描述

3 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

通用唯一标识符 (UUID)是一个 128 位值,即 16 个字节。对于人类可读的显示,许多系统使用带有插入连字符的十六进制文本的规范格式,例如:


123e4567-e89b-12d3-a456-426655440000

这有长度16*2 + 4 = 36。您可以选择省略为您提供的连字符:


fmt.Printf("%x\n", uuid)

fmt.Println(hex.EncodeToString(uuid))


// Output: 32 chars

123e4567e89b12d3a456426655440000

123e4567e89b12d3a456426655440000

您可以选择使用 base32 编码(它使用 1 个符号对 5 位进行编码,而十六进制编码使用 1 个符号对 4 位进行编码):


fmt.Println(base32.StdEncoding.EncodeToString(uuid))


// Output: 26 chars

CI7EKZ7ITMJNHJCWIJTFKRAAAA======

传输时修剪尾随=符号,因此始终为 26 个字符。请注意,您必须"======"在使用base32.StdEncoding.DecodeString().


如果这对您来说仍然太长,您可以使用 base64 编码(用 1 个符号编码 6 位):


fmt.Println(base64.RawURLEncoding.EncodeToString(uuid))


// Output: 22 chars

Ej5FZ-ibEtOkVkJmVUQAAA

请注意,这base64.RawURLEncoding会生成一个 base64 字符串(没有填充),它可以安全地包含在 URL 中,因为符号表中的 2 个额外字符(超出[0-9a-zA-Z])是-和_,它们都可以安全地包含在 URL 中。


不幸的是,base64 字符串可能包含 2 个额外的字符[0-9a-zA-Z]。所以请继续阅读。


解释,转义字符串

如果你对这两个额外的字符不熟悉,你可以选择将你的 base64 字符串转换成一个解释的、转义的字符串,类似于 Go 中的解释字符串文字。例如,如果您想在解释的字符串文字中插入反斜杠,则必须将其加倍,因为反斜杠是表示序列的特殊字符,例如:


fmt.Println("One backspace: \\") // Output: "One backspace: \"

我们可能会选择做类似的事情。我们必须指定一个特殊字符:be it 9。


推理: base64.RawURLEncoding使用 charset: A..Za..z0..9-_,因此9用字母数字字符表示最高代码(十进制 61 = 111101b)。请参阅下面的优势。

因此,只要 base64 字符串包含 a9,请将其替换为99. 并且每当 base64 字符串包含额外字符时,请使用序列而不是它们:


9  =>  99

-  =>  90

_  =>  91

这是一个简单的替换表,可以通过以下值捕获strings.Replacer:


var escaper = strings.NewReplacer("9", "99", "-", "90", "_", "91")

并使用它:


fmt.Println(escaper.Replace(base64.RawURLEncoding.EncodeToString(uuid)))


// Output:

Ej5FZ90ibEtOkVkJmVUQAAA

这会稍微增加长度,因为有时会使用 2 个字符的序列而不是 1 个字符,但好处是只[0-9a-zA-Z]使用字符,如您所愿。平均长度将少于 1 个附加字符:23字符。公平贸易。


逻辑:为简单起见,我们假设所有可能的 uuid 具有相同的概率(uuid 不是完全随机的,所以情况并非如此,但我们将其放在一边,因为这只是一个估计)。最后一个 base64 符号永远不会是可替换的字符(这就是为什么我们选择特殊字符9而不是 like A),21 个字符可能会变成可替换的序列。一个被替换的机会:3 / 64 = 0.047,所以平均而言这意味着 21*3/64 = 0.98 个序列将 1 个字符转换为 2 个字符序列,因此这等于额外字符的数量。


要解码,请使用以下捕获的逆解码表strings.Replacer:


var unescaper = strings.NewReplacer("99", "9", "90", "-", "91", "_")

解码转义的 base64 字符串的示例代码:


fmt.Println("Verify decoding:")

s := escaper.Replace(base64.RawURLEncoding.EncodeToString(uuid))

dec, err := base64.RawURLEncoding.DecodeString(unescaper.Replace(s))

fmt.Printf("%x, %v\n", dec, err)

输出:


123e4567e89b12d3a456426655440000, <nil>

尝试Go Playground上的所有示例。


查看完整回答
反对 回复 2022-01-17
?
函数式编程

TA贡献1807条经验 获得超9个赞

正如这里所建议的那样,如果您只想将一个相当随机的字符串用作 slug,最好不要打扰 UUID。


您可以简单地使用 go 的本机 math/rand 库来制作所需长度的随机字符串:


import (

"math/rand"

"encoding/hex"

)



b := make([]byte, 4) //equals 8 characters

rand.Read(b) 

s := hex.EncodeToString(b)


查看完整回答
反对 回复 2022-01-17
?
元芳怎么了

TA贡献1798条经验 获得超7个赞

另一种选择是math/big。虽然base64有 22 个字符的恒定输出,math/big但可以减少到 2 个字符,具体取决于输入:


package main


import (

   "encoding/base64"

   "fmt"

   "math/big"

)


type uuid [16]byte


func (id uuid) encode() string {

   return new(big.Int).SetBytes(id[:]).Text(62)

}


func main() {

   var id uuid

   for n := len(id); n > 0; n-- {

      id[n - 1] = 0xFF

      s := base64.RawURLEncoding.EncodeToString(id[:])

      t := id.encode()

      fmt.Printf("%v %v\n", s, t)

   }

}

结果:


AAAAAAAAAAAAAAAAAAAA_w 47

AAAAAAAAAAAAAAAAAAD__w h31

AAAAAAAAAAAAAAAAAP___w 18owf

AAAAAAAAAAAAAAAA_____w 4GFfc3

AAAAAAAAAAAAAAD______w jmaiJOv

AAAAAAAAAAAAAP_______w 1hVwxnaA7

AAAAAAAAAAAA_________w 5k1wlNFHb1

AAAAAAAAAAD__________w lYGhA16ahyf

AAAAAAAAAP___________w 1sKyAAIxssts3

AAAAAAAA_____________w 62IeP5BU9vzBSv

AAAAAAD______________w oXcFcXavRgn2p67

AAAAAP_______________w 1F2si9ujpxVB7VDj1

AAAA_________________w 6Rs8OXba9u5PiJYiAf

AAD__________________w skIcqom5Vag3PnOYJI3

AP___________________w 1SZwviYzes2mjOamuMJWv

_____________________w 7N42dgm5tFLK9N8MT7fHC7

https://golang.org/pkg/math/big


查看完整回答
反对 回复 2022-01-17
  • 3 回答
  • 0 关注
  • 885 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信