Gibt es eine Excel-Funktion, um einen Hash-Wert zu erstellen?


26

Ich arbeite mit einer Reihe von Datenlisten, die durch den Dokumentnamen verschlüsselt sind. Die Dokumentnamen sind zwar sehr beschreibend, aber recht umständlich, wenn ich sie anzeigen muss (bis zu 256 Byte sind viel Immobilien), und ich würde gerne ein kleineres Schlüsselfeld erstellen können, das bei Bedarf leicht reproduzierbar ist von einem VLOOKUPanderen Arbeitsblatt oder einer anderen Arbeitsmappe aus ausführen.

Ich denke, ein Hash aus dem Titel, der für jeden Titel einzigartig und reproduzierbar wäre, wäre am besten geeignet. Ist eine Funktion verfügbar oder möchte ich einen eigenen Algorithmus entwickeln?

Irgendwelche Gedanken oder Ideen zu dieser oder einer anderen Strategie?

Antworten:


34

Sie müssen keine eigene Funktion schreiben - andere haben das bereits für Sie getan.
Zum Beispiel habe ich fünf VBA-Hash-Funktionen für diese Stackoverflow-Antwort gesammelt und verglichen

Ich persönlich benutze diese VBA-Funktion

  • Es wird mit =BASE64SHA1(A1)in Excel aufgerufen, nachdem Sie das Makro in ein VBA- Modul kopiert haben
  • benötigt .NET, da es die Bibliothek "Microsoft MSXML" verwendet (mit später Bindung)

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

Anpassen der Hash-Länge

  • Der Hash ist anfangs eine 28 Zeichen lange Unicode-Zeichenfolge (Groß- und Kleinschreibung + Sonderzeichen).
  • Sie passen die Hash-Länge mit dieser Zeile an: Const cutoff As Integer = 5
  • 4-stelliger Hash = 36 Kollisionen in 6895 Zeilen = 0,5% Kollisionsrate
  • 5-stelliger Hash = 0 Kollisionen in 6895 Zeilen = 0% Kollisionsrate

Es gibt auch Hash-Funktionen ( alle drei CRC16-Funktionen ), die kein .NET erfordern und keine externen Bibliotheken verwenden. Aber der Hash ist länger und erzeugt mehr Kollisionen.

Sie können auch einfach diese Beispielarbeitsmappe herunterladen und mit allen 5 Hash-Implementierungen herumspielen. Wie Sie sehen, gibt es auf dem ersten Blatt einen guten Vergleich


1
Sieht großartig aus. Ich habe jedoch nicht genügend VBA-Erfahrung, um die Rückkehr von Excel zu verhindern #NAME?. Code anzeigen> Code ausschneiden und in ein neues Fenster einfügen - im richtigen Arbeitsblatt im Navigator> Als makrofähiges Arbeitsblatt speichern> Schließen und zurück zu Excel ... Fehlt noch etwas? Muss ich es irgendwie kompilieren?
Dwwilson66

Ja ... zur Verdeutlichung ... ich habe es in das neue Codefenster eingefügt, das beim Aufrufen der Registerkarte Arbeitsblatt> Code anzeigen ... angezeigt wurde
Dwwilson66

WooHoo ... das Musterblatt hat geholfen. Mir wurde klar, dass ich den Code in das OBJECT-Fenster und nicht in ein MODULE-Fenster eingefügt hatte. Ich bekomme jetzt Hashes in meine Arbeitsmappe!
Dwwilson66

1
Dies ist ein hervorragendes Werkzeug.
Jay Killeen

1
Sie können das cutoffParametrierte und das Optionale mit einem anderen Standard festlegen, indem Sie es in die Liste der Funktionsparameter verschieben Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) und die Deklaration in der Funktion entfernen.
Kern

9

Ich interessiere mich nicht sehr für Kollisionen, benötige aber einen schwachen Pseudo-Zufallsgenerator für Zeilen, der auf einem Zeichenkettenfeld variabler Länge basiert. Hier ist eine verrückte Lösung, die gut funktioniert hat:

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

Wo Z2ist die Zelle, die den String enthält, den Sie hashen möchten?

"MOD" sollen ein Überlaufen der wissenschaftlichen Notation verhindern. 1009ist eine Primzahl, könnte alles X verwenden, so dass X * 255 < max_int_size. 10 ist beliebig; benutze alles. "Else" -Werte sind willkürlich (hier Ziffern von pi!); benutze alles. Die Position der Zeichen (1,3,5,7,9) ist beliebig. benutze alles.


2
Ehrlich gesagt ist dies die einfachste Antwort. Ich bezweifle, dass Kollisionen ein Problem für die meisten Excel-Anwendungsfälle darstellen.
rollt

3

Für eine einigermaßen kleine Liste können Sie mit den integrierten Excel-Funktionen einen Scrambler (die Hash-Funktion für Arme) erstellen.

Z.B

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

Hier enthalten A1 und B1 einen zufälligen Anfangsbuchstaben und eine zufällige Zeichenkettenlänge.

Ein bisschen herumspielen und prüfen, und in den meisten Fällen können Sie schnell eine funktionsfähige eindeutige ID erhalten.

Funktionsweise : Die Formel verwendet den ersten Buchstaben der Zeichenfolge und einen festen Buchstaben aus der Mitte der Zeichenfolge und verwendet LEN () als Auflockerungsfunktion, um die Wahrscheinlichkeit von Kollisionen zu verringern.

CAVEAT : Dies ist kein Hash, aber wenn Sie etwas schnell erledigen müssen und die Ergebnisse überprüfen können, um festzustellen , dass es keine Kollisionen gibt, funktioniert das ganz gut.

Bearbeiten: Wenn Ihre Zeichenfolgen variable Längen haben sollten (z. B. vollständige Namen), aber aus einem Datenbankdatensatz mit Feldern fester Breite abgerufen werden, möchten Sie dies folgendermaßen tun:

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

damit sind die längen ein sinnvoller scrambler.


1
Gute Antwort! (: "Die Hash-Funktion des armen Mannes", "Einschränkung", "wie es funktioniert" :)
verrückt nach natty

1
Um "die Ergebnisse auf Kollisionen zu überprüfen", können Sie dies einfach durch Ausführen von DATA> REMOVE DUPLICATES versuchen / testen und feststellen, ob es Kollisionen gibt. [offensichtlich / vermutlich, wenn Sie encouter Duplikate tun könnten Sie einfach die obige Funktion für diese iterativ erneut ausgeführt , bis keine Duplikate verbleiben]
nussig über natty

2

Ich verwende dies, was ziemlich gute Ergebnisse mit der Verhinderung von Konflikten liefert, ohne jedes Mal ein Skript ausführen zu müssen. Ich brauchte einen Wert zwischen 0 - 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)))

Es wählt Buchstaben aus der gesamten Zeichenfolge aus, nimmt den Wert jedes dieser Buchstaben, addiert einen Wert (um zu verhindern, dass dieselben Buchstaben an verschiedenen Stellen zu denselben Ergebnissen führen), multipliziert / dividiert jeden Buchstaben und führt eine COS-Funktion über die Summe aus.


1

Sie können dies versuchen. Führen Sie eine Pseudo-Nr. In zwei Spalten aus:

= + WENN (UND (ISBLANK (D3), ISBLANK (E3)), "", CODE (TRIM (D3 & E3)) * LEN (TRIM (D3 & E3)) + CODE (MITTEL (TRIM (D3 & E3), $ A $ 1 * LEN (D3 & E3), 1)) INT (LEN (TRIM (D3 & E3)) $ B $ 1))

Wo A1 und B1 zufällige Samen speichern, die manuell eingegeben wurden: 0


0

Meines Wissens gibt es in Excel keine Hash-Funktion - Sie müssen eine als benutzerdefinierte Funktion in VBA erstellen.

Bitte beachten Sie jedoch, dass für Ihren Zweck die Verwendung eines Hashs meiner Meinung nach nicht erforderlich oder wirklich vorteilhaft ist! VLOOKUPfunktioniert mit 256 Bytes genauso gut wie mit einem kleineren Hash. Sicher, es könnte ein kleines bisschen langsamer sein - ein bisschen, das mit Sicherheit so klein ist, dass es nicht messbar ist. Und dann ist das Hinzufügen der Hash-Werte für Sie und für Excel mühsamer ...


Ja ... ich weiß das, aber nur vom Standpunkt der Präsentation aus würde ich lieber 15 Bytes Hash anzeigen, die 256 Bytes titlein meinem eingefrorenen linken Bereich sind ...
dwwilson66
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.