2009-10-29 4 views
0

J'essaie de représenter le résultat d'un hachage MD5 dans la chaîne la plus courte possible. Il semble que ce soit un gaspillage de le transformer en une chaîne hexagonale et de laisser G à Z aller à perdre.Puis-je construire un BigInt avec un tableau d'octets (Scala)?

Une idée que j'ai eu est d'obtenir le hachage MD5 de mon entrée comme un tableau d'octets et de construire un BigInt avec elle. Je peux alors appeler toString(36), et obtenir le nombre comme base-36 dans une chaîne (-?[0-9a-z]*, le nombre peut être positif ou négatif). Ça marche pour moi.

Le problème est, je ne suis pas sûr qu'un BigInt peut être construit avec n'importe quel tableau d'octets, et je ne peux pas le prouver avec des tests (du moins pas en temps opportun!). Je suppose que oui, parce que je comprends qu'un BigInt peut être de taille arbitraire. Je ne peux pas utiliser cette méthode jusqu'à ce que je sache avec certitude qu'il fonctionnera pour toutes les sorties possibles. Donc, quelqu'un peut-il me dire si cela fonctionnera pour toutes les entrées (ou comment convertir facilement un tableau d'octets pour qu'il puisse être représenté en base 36).

Précision: J'ai la mise en œuvre, je demande sur le comportement sur l'ensemble du domaine (à savoir 00000000000000000000000000000000 à FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)

+0

La mise en œuvre que vous décrivez ne ne fonctionnera pas sur tout le domaine, mais vous pouvez le faire fonctionner par padding la tête du tableau avec un SOH (0x01) octet comme indiqué dans la réponse ci-dessous. –

Répondre

3

Miser sur vos commentaires ci-dessus, la mise en œuvre suivante sera fiable encoder/décoder un tableau d'octets arbitraire:

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) 
    } 

} 

Notez que nous ajoutons un octet 0x01 supplémentaire à la tête du tableau pour éviter les effets secondaires de prendre le complément à deux du tableau d'octets.

EDIT: Les tests impliqués prouver ceci est documenté ici: http://cleverlytitled.blogspot.com/2009/10/scalacheck.html

+0

Désolé pour l'acceptation tardive. Les projets de temps de rechange ne sont malheureusement que pour le temps libre! – Joe

0

Ne serait-Base64 plus courte que Base36? Vous pouvez trouver beaucoup d'implémentations autour.

Mais, pour répondre effectivement à la question:

// 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

Je mets ceci dans un nom de fichier dans une URL que les utilisateurs de Windows peuvent télécharger. Avoir des plafonds mixtes dans Windows est plus difficile que ça en vaut la peine. Merci pour votre réponse, mais je demandais de pouvoir construire un BigInt avec n'importe quel tableau d'octets. J'ai déjà l'implémentation, je pose des questions sur son comportement sur l'ensemble des tableaux d'octets (de 000000000000000000000000000000 à FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) – Joe

+0

Puisque vous avez l'implémentation, tester une boucle ou des valeurs aléatoires et vos cas de coin devrait être simple. Vous constaterez que si l'octet de début est 0x00 et que le deuxième octet n'est pas négatif, ou si l'octet de début est 0xff et le second octet est négatif, cela échouera. –

Questions connexes