How can I shorten a UUID to a specific length?

好久不见. 提交于 2019-12-23 04:27:06

问题


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?


回答1:


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.




回答2:


You can't shorten a UUID.

From Wikipedia

A UUID is a 16-octet (128-bit) number.

In its canonical form, a UUID is represented by 32 lowercase hexadecimal digits.

If you make it any shorter, it's not a UUID any more.

There are various techniques for creating shorter URLs. Just search for "URL shortener" and you'll find any number of gems.




回答3:


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


来源:https://stackoverflow.com/questions/26615900/how-can-i-shorten-a-uuid-to-a-specific-length

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!