如何使用Ruby中的自定义字符集将UUID转换为字符串?

我想根据此处的规范创建一个有效的IFC GUID(IfcGloballyUniqueId): http : //www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcutilityresource/lexical/ifcgloballyuniqueid.htm

它基本上是一个UUID或GUID(128位)映射到一组22个字符,以限制文本文件中的存储空间。

我目前有这个解决方法,但它只是一个近似值:

guid = '';22.times{|i|guid<<'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$'[rand(64)]} 

最好使用ruby SecureRandom生成128位UUID,如本例所示( https://ruby-doc.org/stdlib-2.3.0/libdoc/securerandom/rdoc/SecureRandom.html ):

 SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594" 

根据以下格式,此UUID需要映射到长度为22个字符的字符串:

  1 2 3 4 5 6 0123456789012345678901234567890123456789012345678901234567890123 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$"; 

我完全不明白这一点。 如果将32个字符的长hex数转换为128个字符长的二进制数,则分为22组6位(除了获得剩余的2位的一个?),每个都可以转换为十进制数从0到64? 然后又可以用转换表中的相应字符替换?

我希望有人可以validation我是否在这里正确的轨道。

如果我是,那么Ruby中是否有一种计算速度更快的方法将128位数转换为22位0-64而不是使用所有这些单独的转换?


编辑 :对于有同样问题的人,这是我现在的解决方案:

 require 'securerandom' # possible characters in GUID guid64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$' guid = "" # SecureRandom.uuid: creates a 128 bit UUID hex string # tr('-', ''): removes the dashes from the hex string # pack('H*'): converts the hex string to a binary number (high nibble first) (?) is this correct? # This reverses the number so we end up with the leftover bit on the end, which helps with chopping the sting into pieces. # It needs to be reversed again to end up with a string in the original order. # unpack('b*'): converts the binary number to a bit string (128 0's and 1's) and places it into an array # [0]: gets the first (and only) value from the array # to_s.scan(/.{1,6}/m): chops the string into pieces 6 characters(bits) with the leftover on the end. [SecureRandom.uuid.tr('-', '')].pack('H*').unpack('b*')[0].to_s.scan(/.{1,6}/m).each do |num| # take the number (0 - 63) and find the matching character in guid64, add the found character to the guid string guid << guid64[num.to_i(2)] end guid.reverse 

Base64编码非常接近你想要的,但映射是不同的。 没什么大不了的,你可以解决这个问题:

 require 'securerandom' require 'base64' # Define the two mappings here, side-by-side BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' IFCB64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$' def ifcb64(hex) # Convert from hex to binary, then from binary to Base64 # Trim off the == padding, then convert mappings with `tr` Base64.encode64([ hex.tr('-', '') ].pack('H*')).gsub(/\=*\n/, '').tr(BASE64, IFCB64) end ifcb64(SecureRandom.uuid) # => "fa9P7E3qJEc1tPxgUuPZHm"