microsoft excel 2010
Existe uma função Excel para criar um valor hash
Estou trabalhando com várias listas de dados que são codificadas pelo nome do documento. Os nomes dos documentos, embora muito descritivos, são bastante complicados se eu precisar visualizá-los (até 256 bytes é muito espaço) e adoraria poder criar um campo-chave menor que seja prontamente reproduzível caso eu precise para fazer um VLOOKUP
de outro workset ou pasta de trabalho.
Estou pensando que um hash do título que seria único e reproduzível para cada título seria mais apropriado. Existe uma função disponível ou estou pensando em desenvolver meu próprio algoritmo?
Alguma reflexão ou ideia sobre esta ou outra estratégia?
Não precisa de escrever a sua própria função-outros já o fizeram por si.
Por exemplo, coletei e comparei cinco funções de hash VBA nesta resposta
Pessoalmente,uso esta função VBA
- é chamado com
=BASE64SHA1(A1)
no Excel depois que você copiou a macro para um módulo VBA - 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
Personalização do comprimento do haxixe
- o hash é inicialmente um fio unicode de 28 caracteres de comprimento (sensível a maiúsculas e minúsculas+caracteres especiais)
- Você 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
- hash de 5 dígitos=0 colisões em 6895 linhas=0 % de taxa de colisão
Existem também funções de hash ( todas as três funções CRC16 ) que não requerem .NET e não usam bibliotecas externas. Mas o hash é mais longo e produz mais colisões.
Você também pode baixar esta pasta de trabalho de exemplo e brincar com todas as 5 implementações de hash. Como você vê, há uma boa comparação na primeira folha
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 string que você deseja hash.
"MOD"s existem para evitar o transbordamento para notação científica. 1009
é um primo, pode usar qualquer coisa X para que X*255 < max_int_size
. 10 é arbitrário; usar qualquer coisa. Os valores "Else" são arbitrários (dígitos de pi aqui!); usar qualquer coisa. A localização dos caracteres (1,3,5,7,9) é arbitrária; usar qualquer coisa.