I'd like to use a UUID for database records but if I'm using it for the URL I'd like it to be 5 to 8 characters.
I know I need to use SecureRandom
and base64
, but how do I specify the length I need?
You can use the short-uuid package to generate v4 UUIDs and shorten them for your application's use cases.
You can use base64 encoding and reduce it to 22 characters. If you use base94 you can get it does to 20 characters. If you use the whole range of valid chars fro \u0000 to \ufffd you can reduce it to just 9 characters or 17 bytes. If you don't care about Strings you can use 16, 8-bit bytes.
UUIDs are fixed length. UUIDs are 128-bits in binary. (32 hex digits x 4 bits per hex digit = 128-bits). UUIDs may also be represented in decimal or binary format.
It's 36 characters (32 hex digits + 4 dashes).
You can't get a real UUID down to 5-8 characters, as another answer points out, but you can shorten them somewhat. UUIDs are 128-bit integers which works out to 32 hex digits. You can easily store 6 bits per character and cut the length down to 22 characters, which is what base 64 encoding is. Standard base 64 encoding uses upper and lower case letters, digits, and "+" and "/" to finish it out. If you replace "+" and "/" with "-" and "_" you will end up with a string that doesn't have to be url encoded. You can do it like this (using UUIDTools to create the UUID):
uuid = UUIDTools::UUID.random_create
str = [uuid.raw].pack('m*').tr('+/','-_').slice(0..21)
To get your value back out:
(str + "==\n").tr('-_','+/').unpack('m*').first if str =~ /^[a-zA-Z0-9_\-]{22}$/
That's assuming the UUID can be put into a raw format where it's a string of 16 8-bit characters. Here's an irb session showing a real example:
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>
I use this method on various web sites where I typically use Postgres to generate UUIDs as primary keys for tables and pass them as ids. It doesn't save a lot of space but it does make some URLs fit on one 80 character line where a full UUID in standard format wouldn't. With dashes, a standard UUID is 36 characters so 22 is about 2/3 the size.
I created two single line function based on Michael Chaney
def encode(uuid)
[uuid.tr('-', '').scan(/../).map(&:hex).pack('c*')].pack('m*').tr('+/', '-_').slice(0..21)
end
def decode(short_id)
(short_id.tr('-_', '+/') + '==').unpack('m0').first.unpack('H8H4H4H4H12').join('-')
end
uuid = "355bf501-ffea-4f5a-a9e2-16074de6fcf2"
=> "355bf501-ffea-4f5a-a9e2-16074de6fcf2"
encode(uuid)
=> "NVv1Af_qT1qp4hYHTeb88g"
decode(_)
=> "355bf501-ffea-4f5a-a9e2-16074de6fcf2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With