如何从字节创建 ruby uuid?

How to create ruby uuid from bytes?

C# 包含从字节生成 Guid 的方法:

byte[] bytes = {107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223};
Guid guid = new Guid(bytes); // => {f29b616b-3424-57b6-43df-a3a607af7bdf}

如何编写 ruby 生成与 C# 相同的 uuid 的代码? Ruby:SecureRandom中定义的uuid不接受任何参数。

有时开发过程涉及编写代码,而不仅仅是调用现有库:

bytes.each_with_object([]) do |b, acc|
  acc << [] if acc.size == 0 ||
               acc.size == 1 && acc.last.size == 4 ||
               acc.size > 1 && acc.size < 5 && acc.last.size == 2
  acc.last << b.to_s(16).rjust(2, '0')
end.map.with_index do |e, idx|
  idx < 3 ? e.reverse : e
end.map(&:join).join('-')
#⇒ "f29b616b-3424-57b6-43df-a3a607af7bdf"

第一个近似答案:

a = [107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223]
ah = a.map{ |i| i.to_s(16) }

puts [4,2,2,2,6].inject([]) { |result, idx| result << ah.slice!(0, idx).reverse.join }.join("-")

f29b616b-3424-57b6-df43-df7baf7a6a3
=> nil

几乎可以肯定有一种更简洁的方法可以做到这一点,但这为您提供了一些可以使用的方法。它使用 inject 将生成的 uuid 字符串部分累积到一个数组中,然后将它们连接到 guid 中。

guid的每个块都是字节数组的一个子数组,貌似从lsb到msb排序。

另一种给猫皮的方法,简单易懂:

a = [107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223]

def _guid(ints, reverse=false)
  hexes = ints.map { |b| b.to_s(16).rjust(2, '0') }
  return hexes.reverse.join if reverse
  hexes.join
end

def guid(ints)
  '%s-%s-%s-%s-%s' % [
    _guid(ints[0...4], true),
    _guid(ints[4...6], true),
    _guid(ints[6...8], true),
    _guid(ints[8...10]),
    _guid(ints[10..-1]),
  ]
end

puts guid a # => f29b616b-3424-57b6-43df-a3a607af7bdf

这是一种方法,只使用 sprintf。我不确定我是喜欢它还是讨厌它。

arr = [107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223]

fmt = "%4x%3x%2x%1x-" \
      "%6x%5x-%8x%7x-%9x%10x-" \
      "%11x%12x%13x%14$x%15$x%16$x"

str = sprintf(fmt, *arr)
# => "f29b616b-3424-57b6-43df-a3a607af7bdf"

这使用 sprintf$ 标志来明确指定十六进制数字的顺序,例如%4x 表示 "print the fourth octet in the arguments as two hex digits."

当然,我们可以生成格式字符串:

positions = [[4, 3, 2, 1], [6, 5], [8, 7], [9, 10], 11..16]
fmt = positions.map {|a| a.map {|d| "%#{d}x" }.join }.join("-")
# => "%4x%3x%2x%1x-%6x%5x-%8x%7x-%9x%10x-%11x%12x%13x%14x%15x%16x"

str = sprintf(fmt, *arr)
# => "f29b616b-3424-57b6-43df-a3a607af7bdf"

...但到那时你还不如这样做:

positions = [ [ 3, 2, 1, 0 ], [ 5, 4 ], [ 7, 6 ], [ 8, 9 ], 10..15 ]
str = positions.map {|a| a.map {|n| "%02x" % arr[n] }.join }.join("-")
# => f29b616b-3424-57b6-43df-a3a607af7bdf

您可以在 repl.it 上看到所有这些操作:https://repl.it/@jrunning/FamousRewardingApplescript

这可以通过将字节转换为十六进制字符串数组,将 - 插入正确的位置,然后加入数组来以非常简单的方式完成。

def to_uuid(bytes)
  hex = bytes.map { |b| b.to_s(16).rjust(2, '0') }
  [4, 7, 10, 13].inject(hex) { |hex, n| hex.insert(n, '-') }.join
end

to_uuid([107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223])
# => "6b619bf2-2434-b657-43df-a3a607af7bdf"

给定一个字节数组...

bytes = [107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223];

您可以将字节转换为十六进制,然后用前导 0s...

填充生成的字符串
hex = bytes.map { |b| b.to_s(16).rjust(2, '0') }
# => ["6b", "61", "9b", "f2", "24", "34", "b6", "57", "43", "df", "a3", "a6", "07", "af", "7b", "df"]

然后在正确的地方插入连字符...

[4, 7, 10, 13].inject(hex) { |hex, n| hex.insert(n, '-') }
# => ["6b", "61", "9b", "f2", "-", "24", "34", "-", "b6", "57", "-", "43", "df", "-", "a3", "a6", "07", "af", "7b", "df"]

然后加入数组:

hex.join
# => "6b619bf2-2434-b657-43df-a3a607af7bdf"