一个
通用唯一标识符(UUID)是一个128位的值,即16字节。为了人类可读显示,许多系统使用十六进制文本和插入连字符字符的规范格式,例如:
123e4567-e89b-12d3-a456-426655440000
这个长度为
16*2 + 4 = 36
。你可以选择省略连字符,这样就变成了:
fmt.Printf("%x\n", uuid)
fmt.Println(hex.EncodeToString(uuid))
123e4567e89b12d3a456426655440000
123e4567e89b12d3a456426655440000
你可以选择使用base32编码(与十六进制编码相比,它将5个比特编码为1个符号,而不是4个比特):
fmt.Println(base32.StdEncoding.EncodeToString(uuid))
// Output: 26 chars
CI7EKZ7ITMJNHJCWIJTFKRAAAA======
在传输时去除尾部的=
符号,这样总长度始终为26个字符。请注意,在使用base32.StdEncoding.DecodeString()
解码字符串之前,必须附加"======"
。
如果这仍然太长,您可以使用base64编码(它将6位编码为1个符号):
fmt.Println(base64.RawURLEncoding.EncodeToString(uuid))
// Output: 22 chars
Ej5FZ-ibEtOkVkJmVUQAAA
请注意,
base64.RawURLEncoding
生成的 base64 字符串(不带填充)适合于 URL 包含,因为符号表中的两个额外字符(除了
[0-9a-zA-Z]
)是
-
和
_
,这两个字符都可以安全地包含在 URL 中。
不幸的是,对于您来说,base64 字符串可能包含两个超出
[0-9a-zA-Z]
范围的额外字符。请继续阅读。
解释和转义的字符串
如果您对这两个额外字符感到陌生,您可以选择将 base64 字符串转换为类似于 Go 中解释字符串字面量的
解释和转义的字符串。例如,如果您想在解释字符串字面量中插入反斜杠,则必须将其加倍,因为反斜杠是指示序列的特殊字符,例如:
fmt.Println("One backspace: \\") // Output: "One backspace: \"
我们可以选择做类似的事情。我们必须指定一个特殊字符: 可以是
9
。
推理:
base64.RawURLEncoding
使用字符集:
A..Za..z0..9-_
,因此
9
代表具有字母数字字符的最高代码(61十进制= 111101b)。见下面的优点。
因此,每当base64字符串包含
9
时,请将其替换为
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
而不是像
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上尝试所有的示例。
encoding/base64.NewEncoding
并禁用填充。 - thwd