Posso costruire un BigInt con qualsiasi array di byte (Scala)?
-
10-07-2019 - |
Domanda
Sto cercando di rappresentare il risultato di un hash MD5 nella stringa più breve possibile. Sembra uno spreco trasformarlo in una stringa esadecimale e lasciare che G attraverso Z vada sprecato.
Un'idea che ho avuto è quella di ottenere l'hash MD5 del mio input come una matrice di byte e costruire un BigInt
con esso. Posso quindi chiamare toString (36)
e ottenere il numero come base-36 in una stringa ( -? [0-9a-z] *
, il numero può essere positivo o negativo). Funziona per me.
Il problema è che non sono sicuro che un BigInt
possa essere costruito con qualsiasi array di byte e non posso provarlo con i test (almeno non in modo tempestivo!). Lo presumo, perché capisco che un BigInt può avere dimensioni arbitrarie. Non posso usare questo metodo fino a quando non so per certo che funzionerà per tutti i possibili output. Quindi, qualcuno può dirmi se funzionerà per tutti gli input (o come convertire facilmente un array di byte in modo che possa essere rappresentato nella base 36).
Chiarimento : ho l'implementazione, sto chiedendo informazioni sul comportamento sull'intero dominio (ovvero da 0000000000000000000000000000000000 a FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
Soluzione
Sulla base del tuo feedback sopra, la seguente implementazione codificherà / decodificherà in modo affidabile un array di byte arbitrario:
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)
}
}
Si noti che stiamo aggiungendo un ulteriore 0x01 byte all'intestazione dell'array per evitare che effetti collaterali derivino dal complemento a due dell'array di byte.
EDIT: i test necessari per dimostrarlo sono documentati qui: http: // cleverlytitled.blogspot.com/2009/10/scalacheck.html
Altri suggerimenti
La codifica Base64 non sarebbe più breve di Base36? Puoi trovare molte implementazioni in giro.
Ma, per rispondere effettivamente alla domanda:
// 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!!")
}