一尘不染

在Go中以短字符串形式输出UUID

go

是否有内置方式或合理的标准软件包,可让您将标准UUID转换为短字符串,从而启用较短的URL?

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

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

id = base64.StdEncoding.EncodeToString(myUuid.Bytes())

阅读 1193

收藏
2020-07-02

共1个答案

一尘不染

通用唯一标识符(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个符号编码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: \"

我们可以选择做类似的事情。我们必须指定一个特殊字符:顺其自然9

推理:
base64.RawURLEncoding使用字符集: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上尝试所有示例。

2020-07-02