2013-02-13 14:35:30 +0000 2013-02-13 14:35:30 +0000
27
27

Existe uma função Excel para criar um valor hash?

Estou a trabalhar com uma série de listas de dados que são introduzidas por nome de documento. Os nomes dos documentos, embora muito descritivos, são bastante complicados se precisar de os visualizar (até 256 bytes é muito imobiliário) e gostaria de poder criar um campo chave mais pequeno que seja facilmente reproduzível no caso de precisar de fazer um VLOOKUP a partir de outro workseet ou workbook.

Estou a pensar num hash do título que seria único e reprodutível por cada título seria o mais apropriado. Há alguma função disponível, ou estou a pensar em desenvolver o meu próprio algoritmo?

Alguma reflexão ou ideia sobre esta ou outra estratégia?

Respostas (6)

35
35
35
2013-02-13 14:58:13 +0000

Não precisa de escrever a sua própria função - outros já o fizeram por si.
Por exemplo, recolhi e comparei cinco funções VBA hash nesta resposta de stackoverflow

Pessoalmente utilizo esta função VBA

  • é chamada com =BASE64SHA1(A1) no Excel depois de ter copiado a macro para um módulo VBA módulo
  • requer . NET uma vez que utiliza a biblioteca “Microsoft MSXML” (com encadernação tardia)

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

Personalizando o comprimento do hash

  • o hash é inicialmente uma cadeia unicode de 28 caracteres de comprimento (sensível a maiúsculas e minúsculas + caracteres especiais)
  • Personaliza o comprimento do hash com esta linha: Const cutoff As Integer = 5
  • hash de 4 dígitos = 36 colisões em 6895 linhas = 0. 5 % taxa de colisão
  • 5 dígitos hash = 0 colisões em 6895 linhas = 0 % taxa de colisão

Existem também funções hash as três funções CRC16 ) que não requerem .NET e não utilizam bibliotecas externas. Mas o hash é mais longo e produz mais colisões.

Também pode simplesmente descarregar este exemplo de pasta de trabalho e brincar com todas as 5 implementações de hash. Como pode ver, há uma boa comparação na primeira folha

9
9
9
2016-05-13 19:56:41 +0000

Não me interessa muito as colisões, mas precisava de um fraco pseudorandomizador de linhas com base num campo de cordas de comprimento variável. Aqui está uma solução insana que funcionou bem:

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

Onde Z2 é a célula que contém a corda que se quer hash.

“MOD "s existem para evitar o transbordamento para a notação científica. 1009 é um prime, poderia usar qualquer coisa X para que X\ *255 \ * max_int_size. 10 é arbitrário; usar qualquer coisa. Os valores "Outros” são arbitrários (digitos de pi aqui!); use qualquer coisa. A localização dos caracteres (1,3,5,7,9) é arbitrária; usar qualquer coisa.

3
3
3
2013-06-13 14:48:09 +0000

Para uma lista razoavelmente pequena pode criar um scrambler (função hash do homem pobre) usando funções Excel incorporadas.

E.g.

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

Aqui A1 e B1 contêm uma letra inicial aleatória e um comprimento de string.

Um pouco de manipulação e verificação e, na maioria dos casos, é possível obter uma identificação única e funcional muito rapidamente.

Como funciona : A fórmula utiliza a primeira letra da corda e uma letra fixa retirada do meio da corda e utiliza LEN() como ‘função de leque’ para reduzir a possibilidade de colisões.

CAVEAT : isto é não* um hash, mas quando é preciso fazer algo rapidamente, e pode inspeccionar os resultados para ver que não há colisões, funciona bastante bem.

Editar: Se as suas cordas devem ter comprimentos variáveis (por exemplo, nomes completos) mas são retiradas de um registo de base de dados com campos de largura fixa, vai querer fazê-lo desta forma:

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

para que os comprimentos sejam um codificador significativo.

2
2
2
2018-09-21 16:16:37 +0000

Estou a usar isto, o que dá resultados bastante bons na prevenção de choques sem necessidade de executar um guião de cada vez. Precisava de um valor entre 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)))

Escolhe letras de toda a cadeia, tira o valor de cada uma dessas letras, acrescenta um valor (para evitar que as mesmas letras em lugares diferentes dêem os mesmos resultados), multiplica/divide cada uma e executa uma função COS sobre o total.

1
1
1
2013-11-05 16:24:05 +0000

Pode tentar isto. Execute um Pseudo# em duas colunas:

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

Onde A1 e B1 armazenam sementes aleatórias introduzidas manualmente: 0

0
0
0
2013-02-13 14:40:20 +0000

Tanto quanto sei não há nenhuma função hash incorporada no Excel - seria necessário construir uma como Função Definida pelo Utilizador em VBA.

Contudo, por favor note que para o seu propósito eu não penso que usar um hash seja necessário ou realmente vantajoso! VLOOKUP funcionará tão bem com 256 bytes como com um hash mais pequeno. Claro, pode ser um pouco mais lento - um pouco que é certamente tão pequeno que é imensurável. E depois adicionar os valores de hash é mais esforço para si - e para o Excel…

Questões relacionadas

28
13
13
16
1