代码之家  ›  专栏  ›  技术社区  ›  PreciousBodilyFluids

在ruby/rails中压缩十六进制字符串

  •  2
  • PreciousBodilyFluids  · 技术社区  · 15 年前

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

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

    不是很漂亮。我想遵循Rails的URL约定,但也要将这些ID保留在数据库中。我认为一个很好的折衷办法是使用更多的字符将这些十六进制ID压缩到较短的集合中,这样它们看起来就像:

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

    然后在我的控制器中,我将反转压缩,得到原始的十六进制ID,并使用它来查找记录。

    我的问题是,来回转换这些ID的最佳方法是什么?当然,我希望它们尽可能短,而且URL安全且易于转换。

    谢谢!

    3 回复  |  直到 13 年前
        1
  •  5
  •   mtyaka    15 年前

    您可以用高于 16 使其字符串表示更短。Ruby有内置的支持,支持从 2 高达 36 .

    b36 = '4b3fc1400de0690bf2000001'.hex.to_s(36)
    # => "29a6dblglcujcoeboqp"
    

    要将其转换回24个字符的字符串,可以这样做:

    '%024x' % b36.to_i(36)
    # => "4b3fc1400de0690bf2000001"
    

    为了实现更好的“压缩”,您可以在比 三十六 . 有一些Ruby库可以帮助您实现这一点。 all-your-base 宝石就是这样一个图书馆。

    我推荐BASE 62 表示,因为它只使用 0-9 , a-z A-Z 字符,这意味着默认情况下它是URL安全的。

        2
  •  1
  •   Eli    13 年前

    即使是以62为基数的表示,最终还是会得到16个字符的笨拙ID:

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

    稍微回避Rails约定,另一个折衷办法是使用“url id”的基32表示 created_at 对象的日期。

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

    这样,您就可以获得超短ID(7个字符),而不必跟踪特殊用途的属性(在MongoMapper中,只需添加 timestamps! 在模型中自动 创造在 updated_at 属性)。

        3
  •  0
  •   epochwolf    15 年前

    您可以使用base64来缩短它。请确保您使用的是“-”和“-”而不是“+”和“/”。您还可以切掉padding=。

    从十六进制值转换为基64的代码

    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