几种常见的编码方式

3,276 阅读2分钟

前言

经历了一段时间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个字符表示一个二进制数据。
  • 那么,26=642^6=64可以得出,6位2进制数可以用一个Base64字符代替。进一步,3个字节=24=4Base64字符3个字节=24位=4个Base64字符
  • 结合上面的MD5算法,128位哈希值就可以使用128/621128/6 ≈ 21个字符表示,附上代码。
// 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映射,且能保证口令全局唯一

参考