2015-11-24 40 views
2

我想格式化一個UUIDv4到一個URL友好的字符串。在base16典型的格式是相當長的,有破折號:如何在ruby中一次解壓7位?

xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 

爲了避免破折號和底線我打算用base58(如比特幣呢),所以每個字符編碼完全sqrt(58).floor = 7 bits

我可以收拾UUID成二進制有:

[ uuid.delete('-') ].pack('H*') 

拿到8位無符號整數其:

binary.unpack('C*') 

我怎麼能每7位解壓到8位無符號整數?是否有一種模式可以一次掃描7位,並將高位設置爲0?

+0

這種寶石可以幫助:https://github.com/dougal/base58 –

回答

1
require 'base58' 
uuid ="123e4567-e89b-12d3-a456-426655440000" 
Base58.encode(uuid.delete('-').to_i(16)) 
=> "3fEgj34VWmVufdDD1fE1Su" 

,然後再返回

Base58.decode("3fEgj34VWmVufdDD1fE1Su").to_s(16) 
=> "123e4567e89b12d3a456426655440000" 

一個方便的模式來重建從模板的UUID格式

template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' 
src = "123e4567e89b12d3a456426655440000".each_char 
template.each_char.reduce(''){|acc, e| acc += e=='-' ? e : src.next} 
=> "123e4567-e89b-12d3-a456-426655440000"  
+0

是有感覺過度思考它。 – AJcodez

1

約翰·拉ROOY的答案是偉大的,但我只是想指出如何簡單的Base58算法是因爲我認爲它很整潔。 (鬆散的基礎上的base58寶石,加獎金原int_to_uuid功能):

ALPHABET = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ".chars 
BASE = ALPHABET.size 

def base58_to_int(base58_val) 
    base58_val.chars 
    .reverse_each.with_index 
    .reduce(0) do |int_val, (char, index)| 
     int_val + ALPHABET.index(char) * BASE ** index 
    end 
end 

def int_to_base58(int_val) 
    ''.tap do |base58_val| 
    while int_val > 0 
     int_val, mod = int_val.divmod(BASE) 
     base58_val.prepend ALPHABET[mod] 
    end 
    end 
end 

def int_to_uuid(int_val) 
    base16_val = int_val.to_s(16) 
    [ 8, 4, 4, 4, 12 ].map do |n| 
    base16_val.slice!(0...n) 
    end.join('-') 
end 

uuid = "123e4567-e89b-12d3-a456-426655440000" 
int_val = uuid.delete('-').to_i(16) 
base58_val = int_to_base58(int_val) 
int_val2 = base58_to_int(base58_val) 
uuid2 = int_to_uuid(int_val2) 

printf <<END, uuid, int_val, base_58_val, int_val2, uuid2 
Input UUID: %s 
Input UUID as integer: %d 
Integer encoded as base 58: %s 
Integer decoded from base 58: %d 
Decoded integer as UUID: %s 
END 

輸出:

Input UUID: 123e4567-e89b-12d3-a456-426655440000 
Input UUID as integer: 24249434048109030647017182302883282944 
Integer encoded as base 58: 3fEgj34VWmVufdDD1fE1Su 
Integer decoded from base 58: 24249434048109030647017182302883282944 
Decoded integer as UUID: 123e4567-e89b-12d3-a456-426655440000