如何在ruby中解包大于64位的数字?

时间:2013-06-09 21:18:37

标签: ruby unpack

假设我有一个长约1000个字节的任意字符串。 (我正在研究加密。)如何将其解压缩到BigNum中?我知道如何将其打包成8位数字,比方说或32位数字。

s='I am a grumpy potato'
s.unpack('C*')
[73, 32, 97, 109, 32, 97, 32, 103, 114, 117, 109, 112, 121, 32, 112, 111, 116, 97, 116, 111]
s.upack('L*')
=> [1835081801, 1730175264, 1886221682, 1869619321, 1869898100]

或者,有没有一种简单的方法可以将8位数字组合成一个BigNum?我可以解压缩成一个8位数字的数组,然后乘以8的后续幂来乘以数组的每个元素。但这似乎太复杂了,不是正确的方法。

编辑:将BigNum变回字符串的首选方法是什么?我不是指to_s,我的意思是采用相同的字节模式并将其解释为字符串?

2 个答案:

答案 0 :(得分:4)

我认为你对如何处理它的预感是正确的。打开包装不能处理Bignums;它们在经典上相当棘手,因为它们不适合标准的64位int。

您可以通过以下方式手动“解压缩”它:

str.unpack("C*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (256 ** index)
end

即,反转字节列表(如果在大端系统上),迭代每个字节,并将其值乘以256^position。一旦值变得足够大,Ruby的BigNum就会启动,你可以毫不费力地将字节字符串转换成非常大的数字。

你可以在32位(或64位,如果平台支持它)的块中执行相同的操作:

INT32_MAX = 256 ** [1].pack("L*").size
INT64_MAX = 256 ** [1].pack("Q*").size

str.unpack("L*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (INT32_MAX ** index)
end

str.unpack("Q*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (INT64_MAX ** index)
end

答案 1 :(得分:0)

非常感谢https://stackoverflow.com/a/17014450/204070。对我来说很棒。 答案可以简化为:

str.unpack("C*").inject(0) do |sum, (byte, index)|
  sum * 256 + byte
end