前言
经历了一段时间gap,期间各种好吃懒做,好在新的环境适应的差不多了,也要开始重新进入节奏了。
-
工作中,会遇到编码的场景,例如一些敏感字段需要通过对称/非对称加密算法进行加密、生成一些唯一口令(淘宝口令)之类的场景。
-
还有一个典型的应用就是tinyurl(需要翻墙偶~),功能就是可以把自己常用的网址,通过在tinyurl上形成一个短链接,以后通过短链接访问对应网址。
-
那么,常见的编码方式有哪几种呢?
-
注:笔者最近在学习Go,故代码采用Go编写。
MD5编码
- MD5是一种消息摘要(message-digest)算法,被广泛应用于生成128位(16字节)的Hash值。
- 由于生成的字节流([]byte)直接转换成string会产生乱码,一般用16进制表示,一个16进制使用4位二进制表示,故有32个16进制的值。
func main() {
h := md5.New()
io.WriteString(h, "The fog is getting thicker!")
io.WriteString(h, "And Leon's getting laaarger!")
md5Encoded := h.Sum(nil)
// 乱码
fmt.Println(string(md5Encoded))
// 32个16进制值
fmt.Printf("%x\n", md5Encoded)
// 生成的字节数
fmt.Println(len(md5Encoded))
}
- 通常使用MD5算法生成Hash值后,结合其他编码方式便于呈现,在tinyurl这种场景下单独使用MD5有个缺陷就是生成的字符串太长。
Base62和Base64
- 日常开发中通常用得是Base64编码方式,其原理很简单,使用64个字符表示一个二进制数据。
- 那么,可以得出,6位2进制数可以用一个Base64字符代替。进一步,
- 结合上面的MD5算法,128位哈希值就可以使用个字符表示,附上代码。
// Base64编码
base64Encoded := base64.StdEncoding.EncodeToString(md5Encoded)
// 输出字符串
fmt.Println(base64Encoded)
- 那么Base62、Base64采用哪些字符呢?
a - z A - Z 0 - 9
- 显然
26+26+10
就是62个字符了,Base64编码就是在此基础上增加了两个字符,根据需要有两种不同的字符集合。
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
- 还有个就是'='字符。
Base85和Z85
- 结合上述内容,为了更加减少生成的编码后的字符串长度,可以选择用更多的字符表示。
- Base85除了62个常规字符外,支持以下23个字符。
!#$%&()*+-;<=>?@^_`{|}~
- 但是一些特殊字符,例如
{}
会影响编程语言,或其他解析处理,因此会用其他字符代替。
// z85 golang包
import "github.com/tilinna/z85"
// 方法
func z85Encoding(src []byte) (string, error) {
dst := make([]byte, z85.EncodedLen(len(src)))
_, err := z85.Encode(dst, src)
if err != nil {
return "", err
}
return string(dst), nil
}
// main函数
z85Encoded, _:= z85Encoding(md5Encoded)
fmt.Println(z85Encoded)
- 需要注意的一点就是随着可以使用的字符增多,用于标识的特殊字符减少了。例如,常用
$
作字符串截取之类的,会受影响。
小结
- 对常见的编码方式进行了梳理
- 可以结合tinyURL、淘宝口令生成等场景考虑如何生成较短的口令-URL映射,且能保证口令全局唯一。