web-dev-qa-db-fra.com

Bonne fonction de hachage pour les chaînes

J'essaie de concevoir une bonne fonction de hachage pour les chaînes. Et je pensais que ce serait une bonne idée de résumer les valeurs unicode pour les cinq premiers caractères de la chaîne (en supposant qu'il en ait cinq, sinon arrêtez là où il se termine). Serait-ce une bonne idée ou est-ce une mauvaise idée?

Je le fais à Java, mais je n’imagine pas que cela ferait une grande différence.

132
Leif Andersen

Habituellement, les hachages ne produisent pas de sommes, sinon stop et pots auront le même hash.

et vous ne le limiteriez pas aux n premiers caractères car sinon maison et maisons auraient le même hash.

Généralement, les hashs prennent des valeurs et les multiplient par un nombre premier (ce qui le rend plus susceptible de générer des hachages uniques). Vous pouvez donc faire quelque chose comme:

int hash = 7;
for (int i = 0; i < strlen; i++) {
    hash = hash*31 + charAt(i);
}
135
jonathanasdf

Si c'est un problème de sécurité, vous pouvez utiliser le crypto Java:

import Java.security.MessageDigest;

MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(stringToEncrypt.getBytes());
String encryptedString = new String(messageDigest.digest());
127
Nick

Vous devriez probablement utiliser String.hashCode () .

Si vous voulez vraiment implémenter hashCode vous-même:

Ne soyez pas tenté d'exclure parties significatives d'un objet de le calcul du code de hachage à améliorer performance - Joshua Bloch, Java efficace

Utiliser seulement les cinq premiers caractères est une mauvaise idée. Pensez aux noms hiérarchiques, tels que les URL: ils auront tous le même code de hachage (car ils commencent tous par "http: //", ce qui signifie qu'ils sont stockés sous le même compartiment dans une carte de hachage, affichant des performances épouvantables.

Voici une histoire de guerre paraphrasée sur le String hashCode de " Effective Java ":

La fonction de hachage de chaîne implémentée dans toutes les versions antérieures à 1.2 examinées au plus seize caractères, de manière égale espacés tout au long de la chaîne, en commençant par avec le premier personnage. Pour les grands collections de noms hiérarchiques, telles que les URL, cette fonction de hachage affiché un comportement terrible.

34
Frederik

Si vous le faites en Java, pourquoi le faites-vous? Il suffit d'appeler .hashCode() sur la chaîne

17
Pyrolistical

Guava's HashFunction ( javadoc ) fournit un hachage décent, non crypté.

12
Mike Samuel

Cette fonction fournie par Nick est bonne, mais si vous utilisez une nouvelle chaîne (byte [] bytes) pour effectuer la transformation en chaîne, elle échoue. Vous pouvez utiliser cette fonction pour le faire.

private static final char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

public static String byteArray2Hex(byte[] bytes) {
    StringBuffer sb = new StringBuffer(bytes.length * 2);
    for(final byte b : bytes) {
        sb.append(hex[(b & 0xF0) >> 4]);
        sb.append(hex[b & 0x0F]);
    }
    return sb.toString();
}

public static String getStringFromSHA256(String stringToEncrypt) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(stringToEncrypt.getBytes());
    return byteArray2Hex(messageDigest.digest());
}

Peut-être que cela peut aider quelqu'un

7
Festus Tamakloe
// djb2 hash function
unsigned long hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

sourceLogique de la fonction de hachage djb2 - SO

5
Pratik Deoghare

FNV-1 est supposé être une bonne fonction de hachage pour les chaînes.

Pour les longues chaînes (plus longues que, par exemple, environ 200 caractères), vous pouvez obtenir de bonnes performances avec la fonction MD4 hash. En tant que fonction cryptographique, elle a été interrompue il y a environ 15 ans, mais pour des raisons non cryptographiques, elle est toujours très bonne et étonnamment rapide. Dans le contexte de Java, vous devez convertir les valeurs char de 16 bits en mots de 32 bits, par exemple. en regroupant ces valeurs en paires. Une implémentation rapide de MD4 en Java peut être trouvée dans sphlib . Probablement exagéré dans le contexte d'une tâche en classe, mais sinon cela vaut la peine d'essayer.

4
Thomas Pornin

Si vous voulez voir les implémentations standard du secteur, je regarderais Java.security.MessageDigest .

"Les condensés de messages sont des fonctions de hachage unidirectionnelles sécurisées qui prennent des données de taille arbitraire et génèrent une valeur de hachage de longueur fixe."

3
Dean J

sdbm: cet algorithme a été créé pour la bibliothèque de base de données sdbm (une réimplémentation de ndbm dans le domaine public)

static unsigned long sdbm(unsigned char *str)
{   
    unsigned long hash = 0;
    int c;
    while (c = *str++)
            hash = c + (hash << 6) + (hash << 16) - hash;

    return hash;
}
2
Anchal

voici un lien qui explique de nombreuses fonctions de hachage différentes. Pour l’instant, je préfère la fonction de hachage ELF pour votre problème particulier. Il faut en entrée une chaîne de longueur arbitraire. 

1
Yefei
         public String hashString(String s) throws NoSuchAlgorithmException {
    byte[] hash = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        hash = md.digest(s.getBytes());

    } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hash.length; ++i) {
        String hex = Integer.toHexString(hash[i]);
        if (hex.length() == 1) {
            sb.append(0);
            sb.append(hex.charAt(hex.length() - 1));
        } else {
            sb.append(hex.substring(hex.length() - 2));
        }
    }
    return sb.toString();
}
0
Charaf JRA

Cela évitera toute collision et sera rapide jusqu'à ce que nous utilisions le décalage dans les calculs.

 int k = key.length();
    int sum = 0;
    for(int i = 0 ; i < k-1 ; i++){
        sum += key.charAt(i)<<(5*i);
    }
0