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

时间:2016-06-21 01:18:28

标签: string go encoding uuid

是否有内置方式或合理的标准软件包,允许您将标准UUID转换为可以启用较短网址的短字符串?

即。利用更大范围的字符(例如[A-Za-z0-9])来输出更短的字符串。

我知道我们可以使用base64来编码字节,如下所示,但我正在创建一个看起来像“单词”的字符串,即没有+/:< / p>

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

3 个答案:

答案 0 :(得分:21)

universally unique identifier (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])是-和{ {1}},两者都可以安全地包含在网址中。

不幸的是,base64字符串可能包含超出_的2个额外字符。请继续阅读。

解释,转义字符串

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

[0-9a-zA-Z]

我们可能会选择做类似的事情。我们必须指定一个特殊字符:be fmt.Println("One backspace: \\") // Output: "One backspace: \"

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

99

这是一个简单的替换表,可以通过strings.Replacer

的值捕获
9  =>  99
-  =>  90
_  =>  91

使用它:

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

这会略微增加长度,因为有时会使用2个字符序列而不是1个字符,但增益将是只使用fmt.Println(escaper.Replace(base64.RawURLEncoding.EncodeToString(uuid))) // Output: Ej5FZ90ibEtOkVkJmVUQAAA 字符,如您所愿。 平均长度将少于1个附加字符:[0-9a-zA-Z]字符。 公平交易。

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

要进行解码,请使用以下A

捕获的反向解码表
strings.Replacer

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

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

输出:

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)

尝试Go Playground上的所有示例。

答案 1 :(得分:3)

正如建议的here,如果你只想要一个相当随机的字符串作为slug,最好不要打扰UUID。

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

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


b := make([]byte, 4) //equals 8 charachters
rand.Read(b) 
s := hex.EncodeToString(b)

答案 2 :(得分:1)

另一个选项是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