Esiste una funzione Excel per creare un valore hash?


26

Sto lavorando con una serie di elenchi di dati che sono codificati dal nome del documento. I nomi dei documenti, sebbene molto descrittivi, sono piuttosto ingombranti se devo visualizzarli (fino a 256 byte è un sacco di proprietà immobiliari) e mi piacerebbe essere in grado di creare un campo chiave più piccolo che sia facilmente riproducibile in caso di necessità per fare un VLOOKUPda un'altra workseet o cartella di lavoro.

Sto pensando che un hash dal titolo sarebbe unico e riproducibile per ogni titolo sarebbe più appropriato. È disponibile una funzione o sto cercando di sviluppare il mio algoritmo?

Qualche idea o idea su questa o un'altra strategia?

Risposte:


34

Non hai bisogno di scrivere la tua funzione: altri l'hanno già fatto per te.
Ad esempio, ho raccolto e confrontato cinque funzioni hash VBA su questa risposta di StackOverflow

Personalmente utilizzo questa funzione VBA

  • viene chiamato con =BASE64SHA1(A1)in Excel dopo aver copiato la macro in un modulo VBA
  • richiede .NET poiché utilizza la libreria "Microsoft MSXML" (con associazione tardiva)

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

Personalizzare la lunghezza dell'hash

  • l'hash inizialmente è una stringa unicode lunga 28 caratteri (case sensitive + caratteri speciali)
  • Personalizza la lunghezza dell'hash con questa riga: Const cutoff As Integer = 5
  • Hash a 4 cifre = 36 collisioni in 6895 linee = 0,5% tasso di collisione
  • Hash a 5 cifre = 0 collisioni in 6895 linee = 0% tasso di collisione

Ci sono anche funzioni hash ( tutte e tre le funzioni CRC16 ) che non richiedono .NET e non usano librerie esterne. Ma l'hash è più lungo e produce più collisioni.

Puoi anche scaricare questa cartella di lavoro di esempio e giocare con tutte e 5 le implementazioni di hash. Come vedi c'è un buon confronto sul primo foglio


1
Sembra fantastico. Tuttavia, non ho abbastanza esperienza VBA per impedire il ritorno di Excel #NAME?. Visualizza codice> taglia e incolla il codice in una nuova finestra - all'interno del foglio di lavoro corretto nel navigatore> salva come foglio di lavoro abilitato per le macro> chiudi e ritorna a Excel ... qualcos'altro che mi manca? Devo compilarlo in qualche modo?
dwwilson66,

Sì ... per chiarire ... l'ho incollato nella nuova finestra di codice che è spuntata quando sono andato alla scheda del foglio di lavoro> visualizza codice ... Scarica subito l'esempio, ma vorrei capire perché Excel non riconosce il mio codice
dwwilson66,

WooHoo ... il foglio campione ha aiutato. Mi sono reso conto di aver incollato il codice ed eccellere nella finestra OBJECT, non in una finestra MODULE. Ora sto ricevendo hash nella mia cartella di lavoro!
dwwilson66,

1
Questo è uno strumento eccellente.
Jay Killeen,

1
È possibile rendere il cutoffparametro e facoltativo con un valore predefinito diverso spostandolo verso l'alto nell'elenco dei parametri Funzione Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) e rimuovere la dichiarazione all'interno della funzione.
Core

9

Non mi interessa molto delle collisioni, ma avevo bisogno di uno pseudorandomizzatore debole di righe basato su un campo stringa di lunghezza variabile. Ecco una soluzione folle che ha funzionato bene:

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

Dove si Z2trova la cella contenente la stringa che si desidera hash.

I "MOD" sono lì per evitare di traboccare alla notazione scientifica. 1009è un numero primo, potrebbe usare qualsiasi cosa X in modo che X * 255 < max_int_size. 10 è arbitrario; usa qualsiasi cosa. I valori "Else" sono arbitrari (cifre di pi qui!); usa qualsiasi cosa. La posizione dei personaggi (1,3,5,7,9) è arbitraria; usa qualsiasi cosa.


2
Onestamente questa è la risposta più semplice, dubito che le collisioni siano un problema per la maggior parte dei casi d'uso di Excel.
tira il

3

Per un elenco ragionevolmente piccolo puoi creare uno scrambler (funzione hash di un uomo povero) usando le funzioni di Excel integrate.

Per esempio

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

Qui A1 e B1 contengono una lettera iniziale casuale e una lunghezza della stringa.

Un po 'di armeggiare e controllare e nella maggior parte dei casi è possibile ottenere un ID unico realizzabile abbastanza rapidamente.

Come funziona : la formula utilizza la prima lettera della stringa e una lettera fissa presa dalla stringa centrale e utilizza LEN () come "funzione di smazzamento" per ridurre le possibilità di collisioni.

CAVEAT : questo non è un hash, ma quando hai bisogno di fare qualcosa velocemente e puoi ispezionare i risultati per vedere che non ci sono collisioni, funziona abbastanza bene.

Modifica: se le stringhe devono avere lunghezze variabili (ad es. Nomi completi) ma sono estratte da un record del database con campi a larghezza fissa, ti consigliamo di farlo in questo modo:

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

in modo che le lunghezze siano uno scrambler significativo.


1
Bella risposta! (: "funzione hash del povero", "avvertimento", "come funziona" :)
nocciola circa natty

1
Per "ispezionare i risultati per vedere che non ci sono collisioni" puoi semplicemente provare / testare eseguendo DATI> RIMUOVI DUPLICATI e vedere se ce ne sono. [ovviamente / presumibilmente, se lo fai duplicati encouter si può solo ri-eseguire la funzione di cui sopra per queste iterativamente fino a quando non duplicati sono a sinistra]
nocciola su Natty

2

Sto usando questo che dà risultati abbastanza buoni con la prevenzione dello scontro senza la necessità di eseguire uno script ogni volta. Avevo bisogno di un valore tra 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)))

Prende le lettere dall'altra parte della stringa, prende il valore di ciascuna di quelle lettere, aggiunge un valore (per evitare che le stesse lettere in luoghi diversi producano gli stessi risultati), moltiplica / divide ciascuna ed esegue una funzione COS sul totale.


1

Puoi provare questo. Esegui uno pseudo # su due colonne:

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

Dove A1 e B1 immagazzinano semi casuali inseriti manualmente: 0


0

Per quanto ne sappia, non esiste una funzione hash integrata in Excel: sarebbe necessario crearne una come Funzione definita dall'utente in VBA.

Tuttavia, tieni presente che per il tuo scopo non credo sia necessario o davvero vantaggioso utilizzare un hash! VLOOKUPfunzionerà altrettanto bene su 256 byte come lo sarà su un hash più piccolo. Certo, potrebbe essere un po 'più lento - un po' che è sicuramente così piccolo da essere incommensurabile. E poi aggiungere i valori di hash è più impegno per te - e per Excel ...


sì ... lo so, ma solo dal punto di vista della presentazione, preferirei visualizzare, diciamo, 15 byte di hash di 256 byte titlenel mio riquadro sinistro congelato ...
dwwilson66,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.