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

Jac*_*cob 8 string uuid encoding go

是否有内置方式,或合理的标准包,允许您将标准UUID转换为短链接,以实现更短的URL?

即利用更大范围的字符,例如[A-Za-z0-9]输出更短的字符串.

我知道我们可以使用base64对字节进行编码,如下所示,但是我正在创建一个看起来像"单词"的字符串,即no +/:

id = base64.StdEncoding.EncodeToString(myUuid.Bytes())
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 23

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

123e4567-e89b-12d3-a456-426655440000
Run Code Online (Sandbox Code Playgroud)

这有长度16*2 + 4 = 36.您可以选择省略给您的超值:

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

// Output: 32 chars
123e4567e89b12d3a456426655440000
123e4567e89b12d3a456426655440000
Run Code Online (Sandbox Code Playgroud)

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

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

// Output: 26 chars
CI7EKZ7ITMJNHJCWIJTFKRAAAA======
Run Code Online (Sandbox Code Playgroud)

=在传输时修剪尾随符号,因此总是26个字符.请注意,您必须"======"在使用之前解码字符串base32.StdEncoding.DecodeString().

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

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

// Output: 22 chars
Ej5FZ-ibEtOkVkJmVUQAAA
Run Code Online (Sandbox Code Playgroud)

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

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

解释,转义字符串

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

fmt.Println("One backspace: \\") // Output: "One backspace: \"
Run Code Online (Sandbox Code Playgroud)

我们可能会选择做类似的事情.我们必须指定一个特殊的角色:无论如何9.

推理: base64.RawURLEncoding使用charset : A..Za..z0..9-_,因此9代表具有字母数字字符的最高代码(61十进制= 111101b).见下面的优势.
因此,每当base64字符串包含a时9,请将其替换为99.每当base64字符串包含额外字符时,请使用序列而不是它们:

9  =>  99
-  =>  90
_  =>  91
Run Code Online (Sandbox Code Playgroud)

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

var escaper = strings.NewReplacer("9", "99", "-", "90", "_", "91")
Run Code Online (Sandbox Code Playgroud)

并使用它:

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

// Output:
Ej5FZ90ibEtOkVkJmVUQAAA
Run Code Online (Sandbox Code Playgroud)

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

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

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

var unescaper = strings.NewReplacer("99", "9", "90", "-", "91", "_")
Run Code Online (Sandbox Code Playgroud)

解码转义的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)
Run Code Online (Sandbox Code Playgroud)

输出:

123e4567e89b12d3a456426655440000, <nil>
Run Code Online (Sandbox Code Playgroud)

试试Go Playground上的所有例子.

  • 那个好漂亮。我不知道`base64.RawURLEncoding`和最后的一线替换短划线和下划线可能肯定对某些人有用。感谢您的详细回答。 (2认同)

Kar*_*lom 8

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

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

import (
"math/rand"
"encoding/hex"
)


b := make([]byte, 4) //equals 8 characters
rand.Read(b) 
s := hex.EncodeToString(b)
Run Code Online (Sandbox Code Playgroud)

  • 感谢分享,这可能对某些人有用。然而,这个问题是专门询问渲染 UUID 的。 (3认同)