¿Existe una función de Excel para crear un valor hash?


26

Estoy trabajando con una serie de listas de datos que están codificadas por nombre de documento. Los nombres de los documentos, aunque son muy descriptivos, son bastante engorrosos si necesito verlos (hasta 256 bytes es mucho espacio) y me encantaría poder crear un campo clave más pequeño que sea fácilmente reproducible en caso de que lo necesite para hacer una VLOOKUPdesde otro grupo de trabajo o libro de trabajo.

Estoy pensando que un hash del título que sería único y reproducible para cada título sería lo más apropiado. ¿Hay una función disponible o estoy buscando desarrollar mi propio algoritmo?

¿Alguna idea o idea sobre esta u otra estrategia?

Respuestas:


34

No necesita escribir su propia función; otros ya lo hicieron por usted.
Por ejemplo, recopilé y comparé cinco funciones hash de VBA en esta respuesta de stackoverflow

Personalmente uso esta función VBA

  • se llama con =BASE64SHA1(A1)en Excel después de copiar la macro a un módulo VBA
  • requiere .NET ya que usa la biblioteca "Microsoft MSXML" (con enlace tardío)

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

Personalizar la longitud del hash

  • el hash inicialmente es una cadena unicode de 28 caracteres de longitud (mayúsculas y minúsculas + caracteres especiales)
  • Personaliza la longitud del hash con esta línea: Const cutoff As Integer = 5
  • Hash de 4 dígitos = 36 colisiones en 6895 líneas = 0.5% de tasa de colisión
  • Hash de 5 dígitos = 0 colisiones en 6895 líneas = 0% tasa de colisión

También hay funciones hash ( las tres funciones CRC16 ) que no requieren .NET y no usan bibliotecas externas. Pero el hash es más largo y produce más colisiones.

También puede descargar este libro de trabajo de ejemplo y jugar con las 5 implementaciones de hash. Como veis hay una buena comparación en la primera hoja


1
Se ve muy bien. Sin embargo, no tengo suficiente experiencia en VBA para evitar que Excel regrese #NAME?. Ver código> cortar y pegar código en una nueva ventana: dentro de la hoja de trabajo correcta en el navegador> guardar como hoja de trabajo habilitada para macros> cerrar y volver a sobresalir ... ¿me falta algo más? ¿Necesito compilarlo de alguna manera?
dwwilson66

Sí ... para aclarar ... lo pegué en la nueva ventana de código que apareció cuando fui a la pestaña de la hoja de trabajo> ver código ... Descargando la muestra en este momento, pero me gustaría entender por qué Excel no reconoce mi código
dwwilson66

WooHoo ... la hoja de muestra ayudó. Me di cuenta de que había pegado el código y sobresalía de la ventana OBJETO, no de una ventana MÓDULO. ¡Estoy obteniendo hashes en mi libro de trabajo ahora!
dwwilson66

1
Esta es una excelente herramienta.
Jay Killeen

1
Puede hacer que el cutoffparámetro sea opcional y opcional con un valor predeterminado diferente moviéndolo hacia arriba a la lista de parámetros de Función Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) y eliminando la declaración dentro de la función.
Core

9

No me importan mucho las colisiones, pero necesitaba un pseudoaleatorizador débil de filas basado en un campo de cadena de longitud variable. Aquí hay una solución loca que funcionó bien:

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

¿Dónde Z2está la celda que contiene la cadena que quieres hash?

Los "MOD" están ahí para evitar el desbordamiento a la notación científica. 1009es primo, podría usar cualquier cosa X para que X * 255 < max_int_size. 10 es arbitrario; usa cualquier cosa. Los valores "Else" son arbitrarios (¡dígitos de pi aquí!); usa cualquier cosa. La ubicación de los caracteres (1,3,5,7,9) es arbitraria; usa cualquier cosa.


2
Honestamente, esta es la respuesta más simple, dudo que las colisiones sean un problema para la mayoría de los casos de uso de Excel.
lanza el

3

Para una lista razonablemente pequeña, puede crear un codificador (función hash del pobre) usando las funciones integradas de Excel.

P.ej

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

Aquí A1 y B1 contienen una letra de inicio aleatoria y una longitud de cadena.

Un poco de manipulación y comprobación y, en la mayoría de los casos, puede obtener una identificación única viable rápidamente.

Cómo funciona : la fórmula usa la primera letra de la cadena y una letra fija tomada de la mitad de la cadena y usa LEN () como una 'función de abanico' para reducir la posibilidad de colisiones.

PRUEBA : esto no es un hash, pero cuando necesitas hacer algo rápidamente y puedes inspeccionar los resultados para ver que no hay colisiones, funciona bastante bien.

Editar: si sus cadenas deben tener longitudes variables (por ejemplo, nombres completos) pero se extraen de un registro de base de datos con campos de ancho fijo, querrá hacerlo así:

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

para que las longitudes sean un codificador significativo.


1
¡Gran respuesta! (: "función hash del pobre", "advertencia", "cómo funciona" :)
chiflado sobre natty

1
Para "inspeccionar los resultados para ver que no hay colisiones" , simplemente puede probar / probar esto ejecutando DATOS> ELIMINAR DUPLICADOS y ver si hay alguno. [obviamente / presumiblemente, si fomenta duplicados, simplemente podría volver a ejecutar la función anterior para estos de forma iterativa hasta que no queden duplicados]
chiflado sobre natty

2

Estoy usando esto, que da muy buenos resultados al evitar conflictos sin necesidad de ejecutar un script cada vez. Necesitaba un valor entre 0 y 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)))

Selecciona letras de la cadena, toma el valor de cada una de esas letras, agrega un valor (para evitar que las mismas letras en diferentes lugares den los mismos resultados), multiplica / divide cada una y ejecuta una función COS sobre el total.


1

Puedes probar esto. Ejecute un Pseudo # en dos columnas:

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

Donde A1 y B1 almacenan semillas aleatorias ingresadas manualmente: 0


0

Que yo sepa, no hay una función hash integrada en Excel: necesitaría crear una como una función definida por el usuario en VBA.

Sin embargo, tenga en cuenta que para su propósito, ¡no creo que usar un hash sea obligatorio o realmente ventajoso! VLOOKUPfuncionará igual de bien en 256 bytes que en un hash más pequeño. Claro, puede ser un poco más lento, un bit que es tan pequeño que es inconmensurable. Y luego agregar los valores hash es más esfuerzo para usted, y para Excel ...


sí ... lo sé, pero solo desde el punto de vista de la presentación, prefiero mostrar, digamos, 15 bytes de hash de esos 256 bytes titleen mi panel izquierdo congelado ...
dwwilson66
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.