在Ruby/Rails中压缩十六进制字符串

4

我正在构建一个Rails应用程序,使用MongoDB作为后端。MongoDB默认会为其记录生成24个字符的十六进制ID,以便更容易进行分片,因此我的URL看起来像:

example.com/companies/4b3fc1400de0690bf2000001/employees/4b3ea6e30de0691552000001

这并不是很美观。我想坚持使用Rails的url约定,但也希望将这些id保留在数据库中。我认为一个很好的折中方案是使用更多字符来压缩这些十六进制id以形成更短的集合,使其看起来像:

example.com/companies/3ewqkvr5nj/employees/9srbsjlb2r

然后在我的控制器中,我会反向压缩,获取原始十六进制 ID,并使用它来查找记录。

我的问题是,将这些 ID 来回转换的最佳方式是什么?当然,我希望它们尽可能短,同时也要安全可用于 URL 并且易于转换。

谢谢!

3个回答

6
你可以使用高于16进制的进制来表示十六进制ID,以使其字符串表示更短。Ruby内置支持从2到36的进制运算。
b36 = '4b3fc1400de0690bf2000001'.hex.to_s(36)
# => "29a6dblglcujcoeboqp"

要将其转换回24个字符的字符串,您可以这样做:
'%024x' % b36.to_i(36)
# => "4b3fc1400de0690bf2000001"

为了实现更好的“压缩”,您可以使用高于36进制的基数来表示id。有一些Ruby库可以帮助您完成这项工作。其中之一是all-your-base gem。
我建议使用基数62表示,因为它只使用0-9、a-z和A-Z字符,这意味着它默认情况下是URL安全的。

1

即便使用基于62进制的表示方法,最终仍然会得到难以管理的16位字符ID:

'4b3fc1400de0690bf2000001'.hex.to_base_62  
# => "UHpdfMzq7jKLcvyr"

稍微违反Rails的惯例,另一个妥协是使用对象created_at日期的32进制表示作为“URL id”。

aCompany.created_at
# => Sat Aug 13 20:05:35 -0500 2011
aCompany.created_at.to_i.to_s(32)
# => "174e7qv"

这样做可以获得超短的ID(7个字符),而无需跟踪特殊属性(在MongoMapper中,只需在模型中添加timestamps!即可自动获取created_atupdated_at属性)。


0

您可以使用base64使其更短。确保您使用'-'和'_'代替'+'和'/'。您还可以去掉填充=。

将十六进制值转换为base64的代码

def MD5hex2base64(str)
  h1=[].clear

  # split the 32 byte hex into a 16 byte array
  16.times{ h1.push(str.slice!(0,2).hex) }
  # pack (C* = unsigned char), (m = base64 encoded output)
  [h1.pack("C*")].pack("m")
end

我该怎么做?我尝试在字符串ID上使用Base64.encode64,但这只会使它们变得更长。 - PreciousBodilyFluids
此代码片段展示了如何实现 http://rubyforge.org/snippet/detail.php?type=snippet&id=33 - NA.
2
Base64.encode64会使ID变长,因为您将它们用作字符串而不是二进制数据。 - epochwolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接