mah*_*off 5 ruby base64 encoding
我想做一些类似的事情,fingerprint = Digest::SHA256.base64digest(str)但是要使用base62而不是base64。如何有效地构建任何字符串的唯一以base62编码的字符串哈希?
Pat*_*ity 11
Base 64 广泛用于编码二进制数据,因为 6 位正好适合一个字符,但仍有足够的可打印 ASCII 字符来表示所有可能的模式。换句话说,64 个可用字符代表从十进制 0 到十进制 63 的所有 64 种不同的位模式。
基于大小为 62 的字母表不太适合这一事实,将二进制数据编码为 base 62 存在几个问题。您可以将摘要算法中的二进制数据映射到 32 位块,然后将这些 5 位块中的每一个分配给一个字符。但是,这意味着“v”上方的字符将不再使用,因此您实际上最终会使用 base 32 编码。
在效率方面,base 62甚至永远不会接近 base64。Base 64 编码非常简单:取 6 位,将它们映射到一个字符上,重复直到完成。这太简单了,因为 64 是 2 的幂。但是,对于以 62 为底的,您将必须转换为整数并开始在每一步中结转“余数”,因为模式不能均匀地拟合。
所以我的建议,你可能不喜欢,是使用不同的编码。
——
例如,如果您需要 url 安全编码,则可以使用以下方法之一:
# sample string
str = 'foo'
# original base 64 method for comparison
Digest::SHA256.base64digest(str)
#=> "LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564="
# url safe variant (no slash or plus characters)
Base64.urlsafe_encode64(Digest::SHA256.digest(str))
#=> "LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564="
# hexadecimal (base 16)
Digest::SHA256.hexdigest(str)
#=> "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
# or base 32
# gem install base32
require 'base32'
Base32.encode(Digest::SHA256.digest(str))
#=> "FQTLI23I77DI76M3IU6B2MCBGQJUELLQMSB37IHZRJPIQYTG46XA===="
# or with direct url encoding
# not pretty, but url safe!
require 'open-uri'
URI::encode(Digest::SHA256.digest(str))
#=> ",&%B4kh%FF%C6%8F%F9%9BE%3C%1D0A4%13B-pd%83%BF%A0%F9%8A%5E%88bf%E7%AE"
# or url url escaped base 64
# not pretty, but url safe!
require 'cgi'
CGI::escape(Digest::SHA256.base64digest(str))
#=> "LCa0a2j%2Fxo%2F5m0U8HTBBNBNCLXBkg7%2Bg%2BYpeiGJm564%3D"
Run Code Online (Sandbox Code Playgroud)
——
编辑:这是一个非常非常非常低效的 base62 实现;-)
# gem install base62
require 'base62'
def pack_int(str)
str.unpack('C*').each_with_index.reduce(0){|r,(x,i)| r + (x << 8*i) }
end
def unpack_int(int)
n = (Math.log2(int)/8).ceil
n.times.map{|i| (int >> 8*i) & 255 }.pack('C*')
end
def base62_encode(str)
Base62.encode(pack_int(str))
end
def base62_decode(encoded)
unpack_int(Base62.decode(encoded))
end
str = "foo"
# encode
digest = Digest::SHA256.digest(str)
fingerprint = base62_encode(digest)
#=> "fTSIMrZT3fDTvW7XDBq1b7nhWa24Zl55EVpsaO3TBBE"
# decode
recovered_digest = base62_decode(fingerprint)
#=> ",&\xB4kh\xFF\xC6\x8F\xF9\x9BE<\x1D0A4\x13B-pd\x83\xBF\xA0\xF9\x8A^\x88bf\xE7\xAE"
digest == recovered_digest
#=> true
Run Code Online (Sandbox Code Playgroud)