是否有内置方式或合理的标准软件包,允许您将标准UUID转换为可以启用较短网址的短字符串?
即。利用更大范围的字符(例如[A-Za-z0-9]
)来输出更短的字符串。
我知道我们可以使用base64来编码字节,如下所示,但我正在创建一个看起来像“单词”的字符串,即没有+
和/
:< / p>
id = base64.StdEncoding.EncodeToString(myUuid.Bytes())
答案 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