0

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

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

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

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字符长的十六进制数是否应该转换为128字符长的二进制数,然后分为22组6位(除了获得剩余2位的一组?),每个都可以转换为十进制数从 0 到 64?那么哪个又可以被转换表中的相应字符替换?

我希望有人可以验证我是否在正确的轨道上。

如果我是,在 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
4

1 回答 1

0

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"
于 2017-12-13T23:01:39.890 回答