UUIDを指定の長さに短縮するにはどうすればよいですか?
概要
データベース レコードに UUID を使用したいのですが、URL に使用する場合は 5 ~ 8 文字にしたいと考えています。
SecureRandom と Base64 を使用する必要があることはわかっていますが、必要な長さを指定するにはどうすればよいですか?
解決策
別の回答で指摘されているように、実際の UUID を 5 ~ 8 文字まで取得することはできませんが、多少短縮することはできます。 UUID は 128 ビットの整数で、16 進数 32 桁になります。 1 文字あたり 6 ビットを簡単に保存し、長さを 22 文字 (Base 64 エンコーディング) に短縮することができます。標準の Base 64 エンコードでは、大文字と小文字、数字、および「+」と「/」を使用して仕上げます。 「+」と「/」を「-」と「_」に置き換えると、URL エンコードする必要のない文字列になります。次のように実行できます (UUIDTools を使用して UUID を作成します)。
uuid = UUIDTools::UUID.random_create
str = [uuid.raw].pack('m*').tr('+/','-_').slice(0..21)
値を取り戻すには:
(str + "==\n").tr('-_','+/').unpack('m*').first if str =~ /^[a-zA-Z0-9_\-]{22}$/
これは、UUID を 16 個の 8 ビット文字の文字列である生の形式にできることを前提としています。実際の例を示す IRB セッションは次のとおりです。
2.1.1 :016 > uuid=UUIDTools::UUID.random_create
=> #<UUID:0x83f1e98c UUID:20d07b6c-52af-4e53-afea-6b3ad0d0c627>
2.1.1 :017 > uuid.raw
=> " \xD0{lR\xAFNS\xAF\xEAk:\xD0\xD0\xC6'"
2.1.1 :018 > str = [uuid.raw].pack('m*').tr('+/','-_').slice(0..21)
=> "INB7bFKvTlOv6ms60NDGJw"
2.1.1 :019 > uuid2 = (str + "==\n").tr('-_','+/').unpack('m*').first
=> " \xD0{lR\xAFNS\xAF\xEAk:\xD0\xD0\xC6'"
2.1.1 :022 > UUIDTools::UUID.parse_raw(uuid2)
=> #<UUID:0x849e6b44 UUID:20d07b6c-52af-4e53-afea-6b3ad0d0c627>
私はこの方法をさまざまな Web サイトで使用しており、通常は Postgres を使用してテーブルの主キーとして UUID を生成し、ID として渡します。多くのスペースを節約するわけではありませんが、標準形式の完全な UUID では収まらない一部の URL が 80 文字の 1 行に収まるようになります。ダッシュを使用すると、標準の UUID は 36 文字になるため、22 文字はその約 2/3 のサイズになります。