Existe-t-il une fonction Excel pour créer une valeur de hachage?

26

Je travaille avec un certain nombre de listes de données qui sont saisies par nom de document. Les noms des documents, bien que très descriptifs, sont assez encombrants si je dois les afficher (jusqu'à 256 octets, c'est beaucoup de biens immobiliers) et j'aimerais pouvoir créer un champ de clés plus petit qui est facilement reproductible au cas où j'aurais besoin pour faire un à VLOOKUPpartir d'un autre workseet ou classeur.

Je pense qu'un hachage du titre qui serait unique et reproductible pour chaque titre serait le plus approprié. Y a-t-il une fonction disponible ou est-ce que je cherche à développer mon propre algorithme?

Des pensées ou des idées sur cette stratégie ou sur une autre?

dwwilson66
la source

Réponses:

34

Vous n'avez pas besoin d'écrire votre propre fonction - d'autres l'ont déjà fait pour vous.
Par exemple, j'ai collecté et comparé cinq fonctions de hachage VBA sur cette réponse stackoverflow

Personnellement, j'utilise cette fonction VBA

  • son appelé avec =BASE64SHA1(A1)dans Excel après avoir copié la macro dans un module VBA
  • nécessite .NET car il utilise la bibliothèque "Microsoft MSXML" (avec liaison tardive)

Public Function BASE64SHA1(ByVal sTextToHash As String)

    Dim asc As Object
    Dim enc As Object
    Dim TextToHash() As Byte
    Dim SharedSecretKey() As Byte
    Dim bytes() As Byte
    Const cutoff As Integer = 5

    Set asc = CreateObject("System.Text.UTF8Encoding")
    Set enc = CreateObject("System.Security.Cryptography.HMACSHA1")

    TextToHash = asc.GetBytes_4(sTextToHash)
    SharedSecretKey = asc.GetBytes_4(sTextToHash)
    enc.Key = SharedSecretKey

    bytes = enc.ComputeHash_2((TextToHash))
    BASE64SHA1 = EncodeBase64(bytes)
    BASE64SHA1 = Left(BASE64SHA1, cutoff)

    Set asc = Nothing
    Set enc = Nothing

End Function

Private Function EncodeBase64(ByRef arrData() As Byte) As String

    Dim objXML As Object
    Dim objNode As Object

    Set objXML = CreateObject("MSXML2.DOMDocument")
    Set objNode = objXML.createElement("b64")

    objNode.DataType = "bin.base64"
    objNode.nodeTypedValue = arrData
    EncodeBase64 = objNode.text

    Set objNode = Nothing
    Set objXML = Nothing

End Function

Personnalisation de la longueur du hachage

  • le hachage est initialement une chaîne unicode de 28 caractères (sensible à la casse + caractères spéciaux)
  • Vous personnalisez la longueur du hachage avec cette ligne: Const cutoff As Integer = 5
  • Hachage à 4 chiffres = 36 collisions sur 6895 lignes = 0,5% de taux de collision
  • Hachage à 5 chiffres = 0 collision sur 6895 lignes = 0% de taux de collision

Il existe également des fonctions de hachage ( les trois fonctions CRC16 ) qui ne nécessitent pas .NET et n'utilisent pas de bibliothèques externes. Mais le hachage est plus long et produit plus de collisions.

Vous pouvez également simplement télécharger cet exemple de classeur et jouer avec les 5 implémentations de hachage. Comme vous voyez, il y a une bonne comparaison sur la première feuille

nixda
la source
1
Ça a l'air super. Cependant, je n'ai pas assez d'expérience VBA pour empêcher Excel de revenir #NAME?. Afficher le code> couper et coller le code dans une nouvelle fenêtre - dans la feuille de calcul correcte dans le navigateur> enregistrer en tant que feuille de calcul compatible avec les macros> fermer et revenir à Excel ... quoi que ce soit qui me manque? Dois-je le compiler d'une manière ou d'une autre?
dwwilson66
Oui ... pour clarifier ... je l'ai collé dans la nouvelle fenêtre de code qui est apparue lorsque je suis allé dans l'onglet feuille de calcul> voir le code ... Téléchargement de l'exemple en ce moment, mais je voudrais comprendre pourquoi Excel ne reconnaît pas mon code
dwwilson66
WooHoo ... l'exemple de feuille a aidé. J'ai réalisé que j'avais collé le code dans et excelé la fenêtre OBJECT, pas une fenêtre MODULE. Je reçois des hachages dans mon classeur maintenant!
dwwilson66
1
Ceci est un excellent outil.
Jay Killeen
1
Vous pouvez rendre le cutoffparamétré et facultatif avec une valeur par défaut différente en le déplaçant vers la liste des paramètres de fonction Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) et en supprimant la déclaration à l'intérieur de la fonction.
Core
9

Je ne me soucie pas beaucoup des collisions, mais j'avais besoin d'un faible pseudo-aléatoire de lignes basé sur un champ de chaîne de longueur variable. Voici une solution folle qui a bien fonctionné:

=MOD(MOD(MOD(MOD(MOD(IF(LEN(Z2)>=1,CODE(MID(Z2,1,1))+10,31),1009)*IF(LEN(Z2)>=3,CODE(MID(Z2,3,1))+10,41),1009)*IF(LEN(Z2)>=5,CODE(MID(Z2,5,1))+10,59),1009)*IF(LEN(Z2)>=7,CODE(MID(Z2,7,1))+10,26),1009)*IF(LEN(Z2)>=9,CODE(MID(Z2,9,1))+10,53),1009)

Où se Z2trouve la cellule contenant la chaîne que vous souhaitez hacher.

Les "MOD" sont là pour éviter de déborder sur la notation scientifique. 1009est un nombre premier, pourrait utiliser n'importe quoi X pour que X * 255 < max_int_size. 10 est arbitraire; utiliser quoi que ce soit. Les valeurs "Else" sont arbitraires (les chiffres de pi ici!); utiliser quoi que ce soit. L'emplacement des caractères (1,3,5,7,9) est arbitraire; utiliser quoi que ce soit.

Lâche anonyme
la source
2
Honnêtement, c'est la réponse la plus simple, je doute que les collisions soient un problème pour la plupart des cas d'utilisation Excel.
roule
3

Pour une liste raisonnablement petite, vous pouvez créer un brouilleur (fonction de hachage du pauvre) à l'aide des fonctions Excel intégrées.

Par exemple

 =CODE(A2)*LEN(A2) + CODE(MID(A2,$A$1,$B$1))*LEN(MID(A2,$A$1,$B$1))

Ici, A1 et B1 contiennent une lettre de début aléatoire et une longueur de chaîne.

Un peu de tripotage et de vérification et dans la plupart des cas, vous pouvez obtenir rapidement un identifiant unique réalisable.

Fonctionnement : la formule utilise la première lettre de la chaîne et une lettre fixe tirée du milieu de la chaîne et utilise LEN () comme «fonction de ventilation» pour réduire les risques de collisions.

CAVEAT : ce n'est pas un hachage, mais lorsque vous devez faire quelque chose rapidement et que vous pouvez inspecter les résultats pour voir qu'il n'y a pas de collisions, cela fonctionne très bien.

Edit: Si vos chaînes doivent avoir des longueurs variables (par exemple des noms complets) mais sont extraites d'un enregistrement de base de données avec des champs de largeur fixe, vous voudrez le faire comme ceci:

 =CODE(TRIM(C8))*LEN(TRIM(C8))
       +CODE(MID(TRIM(C8),$A$1,1))*LEN(MID(TRIM(C8),$A$1,$B$1))

de sorte que les longueurs sont un brouilleur significatif.

Assad Ebrahim
la source
1
Très bonne réponse! (: "fonction de hachage du pauvre", "mise en garde", "comment cela fonctionne" :)
folle de natty
1
Pour "inspecter les résultats pour voir qu'il n'y a pas de collisions", vous pouvez simplement essayer / tester cela en exécutant DATA> REMOVE DUPLICATES et voir s'il y en a. [évidemment / probablement, si vous faites des doublons encouter vous pouvez simplement ré-exécuter la fonction ci - dessus pour ces itérativement jusqu'à ce qu'aucun duplicata sont laissés]
nutty à propos natty
2

J'utilise ceci qui donne de très bons résultats avec la prévention des conflits sans avoir besoin d'exécuter un script à chaque fois. J'avais besoin d'une valeur entre 0 et 1.

=ABS(COS((CODE(MID(A2,ROUNDUP(LEN(A2)/9,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)/5,0),1))+100)/CODE(MID(A2,ROUNDUP(LEN(A2)/3,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)*8/9,0),1))+25)/CODE(MID(A2,ROUNDUP(LEN(A2)*6/9,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)*4/9,0),1))-25))/LEN(A2)+CODE(A2)))

Il sélectionne les lettres de la chaîne, prend la valeur de chacune de ces lettres, ajoute une valeur (pour éviter que les mêmes lettres à différents endroits donnent les mêmes résultats), multiplie / divise chacune et exécute une fonction COS sur le total.

Ant Cole
la source
1

Vous pouvez essayer ça. Exécutez un pseudo # sur deux colonnes:

= + IF (AND (ISBLANK (D3), ISBLANK (E3)), "", CODE (TRIM (D3 & E3)) * LEN (TRIM (D3 & E3)) + CODE (MID (TRIM (D3 & E3), $ A $ 1 * LEN) (D3 & E3), 1)) INT (LEN (TRIM (D3 & E3)) $ B $ 1))

Où A1 et B1 stockent des graines aléatoires saisies manuellement: 0

Michael Polubinski
la source
0

À ma connaissance, il n'y a pas de fonction de hachage dans Excel - vous devez en créer une en tant que fonction définie par l'utilisateur dans VBA.

Cependant, veuillez noter que pour votre objectif, je ne pense pas que l'utilisation d'un hachage soit requise ou vraiment avantageuse! VLOOKUPfonctionnera aussi bien sur 256 octets que sur un hachage plus petit. Bien sûr, il pourrait être un tout petit peu plus lent - un bit qui est à coup sûr si petit qu'il est incommensurable. Et puis, ajouter les valeurs de hachage représente plus d'efforts pour vous - et pour Excel ...

Peter Albert
la source
ouais ... Je sais ça, mais juste du point de vue de la présentation, je préfère afficher, disons, 15 octets de hachage dont 256 octets titledans mon volet gauche gelé ...
dwwilson66