我可以用任何字节数组(Scala)构造一个BigInt吗?

问题描述:

我试图用尽可能短的字符串来表示MD5哈希的结果。把它变成一个十六进制字符串并让G到Z去浪费似乎是一种浪费。我可以用任何字节数组(Scala)构造一个BigInt吗?

一个想法我已经是让我作为一个字节数组输入的MD5哈希,构建与它BigInt。然后我可以调用toString(36),并获得一个字符串作为基36的数目(-?[0-9a-z]*,数目可以是正或负)。这个对我有用。

问题是,我不确定BigInt可以用任何字节数组构建,而且我无法通过测试来证明它(至少不是及时的!)。我认为是这样,因为我知道BigInt可以是任意大小的。我不能使用这种方法,直到我确信它可以用于所有可能的输出。那么,谁能告诉我它是否适用于所有输入(或者如何轻松转换一个字节数组,以便可以用基数36表示)。

澄清:我实现,我问的是行为在整个域(即00000000000000000000000000000000到FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)

+0

你形容绝不在整个域工作的实施,但你可以把它用一个SOH填充数组的头工作( 0x01)字节,如下面的答案中所示。 – 2009-10-30 14:21:05

你上面的反馈大厦下面的实现将可靠的编码/解码任意字节数组:

package blevins.example 

object BigIntEncoder { 
    val radix = 36 

    implicit def byteArrayToString(ba: Array[Byte]): String = { 
    new java.math.BigInteger(addByte(ba)).toString(radix) 
    } 

    implicit def stringToByteArray(s: String): Array[Byte] = { 
    stripByte(new java.math.BigInteger(s, radix).toByteArray) 
    } 

    def addByte(ba: Array[Byte]): Array[Byte] = { 
    val h = new Array[Byte](1) 
    h(0) = 0x01 
    h ++ ba 
    } 

    def stripByte(ba: Array[Byte]): Array[Byte] = { 
    ba.slice(1,ba.size) 
    } 

} 

请注意,我们正在增加一个额外的0x01字节到数组的头部,以避免任何副作用来获取字节数组的二进制补码。

编辑:参与证明了这一点,测试记录在这里:http://cleverlytitled.blogspot.com/2009/10/scalacheck.html

+0

对不起,迟到接受。备用时间项目只能用于业余时间! – Joe 2009-11-07 14:41:57

会不会Base64编码比Base36更短?你可以找到大量的实现。

但是,实际上回答这个问题:

// Make a big randomly-filled byte array 
    val random = scala.util.Random 
    val arraySize = 8543 
    val bytes: Array[Byte] = new Array[Byte](arraySize) // make some big array 
    random.nextBytes(bytes) // fill it randomly 

    // Make a BigInt out of it and the corresponding base36 string representation 
    val bi: BigInt = new BigInt(new java.math.BigInteger(bytes)) 
    val strRep: String = bi.toString(36) 

    // Make a new BigInt out of the string rep. Does it match? 
    val bi2: BigInt = new BigInt(new java.math.BigInteger(strRep, 36)) 
    if (bi == bi2) { 
     println("yippee!!") 
    } 

    // Make a new byte array out of the BigInt. Does it match the original array? 
    val bytes2: Array[Byte] = bi2.toByteArray 
    if (bytes deepEquals bytes2) { 
     println("yippee again!!") 
    } 
+0

我把这个放入一个Wi​​ndows用户可以下载的URL中的文件名。在Windows中混合使用大写字符比它的价值更麻烦。 感谢您的回答,但我问的是能够构建一个BIGINT任何字节数组。我已经实现,我想咨询一下这是在整个一组的字节数组(即从00000000000000000000000000000000到FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) – Joe 2009-10-29 19:35:30

+0

行为,因为你必须执行,测试循环或随机值和你的角落情况下应该是简单的。你会发现,如果前导字节是0x00,而第二个字节不是负数,或者前导字节是0xff,而第二个字节是负数,则会失败。 – 2009-10-30 02:21:13