有Excel函数可以创建哈希值吗?


26

我正在处理许多由文档名称作为关键字的数据列表。文档名称虽然具有很强的描述性,但是如果我需要查看它们,则会非常麻烦(最多256个字节是不动产),而且我希望能够创建一个较小的键字段,以便在需要时可以轻松重现做一个VLOOKUP从另一个workseet或工作簿。

我认为标题中的哈希对于每个标题而言都是唯一且可复制的将是最合适的。是否有可用的功能,或者我正在考虑开发自己的算法?

对这个或其他策略有什么想法或想法吗?

Answers:


34

您无需编写自己的函数-其他人已经为您完成了此任务。
例如,我在此stackoverflow答案中收集并比较了五个VBA哈希函数

我个人使用此VBA功能

  • =BASE64SHA1(A1)将宏复制到VBA 模块后,在Excel中调用
  • 需要.NET,因为它使用库“ Microsoft MSXML”(具有后期绑定)

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

自定义哈希长度

  • 哈希最初是28个字符长的unicode字符串(区分大小写+特殊字符)
  • 您可以使用以下行自定义哈希长度: Const cutoff As Integer = 5
  • 4位数字的哈希= 6895行中的36次碰撞= 0.5%的碰撞率
  • 5位哈希= 6895行中的0次碰撞= 0%的碰撞率

还有一些哈希函数(所有三个CRC16函数)都不需要.NET且不使用外部库。但是哈希更长,并且产生更多的冲突。

您也可以只下载此示例工作簿并试用所有5种哈希实现。如您所见,第一张纸上有一个很好的比较


1
看起来很棒。但是,我没有足够的VBA经验来阻止Excel返回#NAME?。查看代码>剪切代码并将其粘贴到新窗口中-在导航器中的正确工作表中>另存为启用了宏的工作表>关闭并返回到excel ...还有其他我想念的东西吗?我需要以某种方式进行编译吗?
dwwilson66

是的...要澄清...我将其粘贴到新的代码窗口中,该窗口在进入“工作表”选项卡>查看代码时弹出。现在正在下载示例,但是我想了解为什么excel无法识别我的代码
dwwilson66

哇...示例表帮助了。实现了,我将代码粘贴到了excel OBJECT窗口中,而不是MODULE窗口中。我的工作簿中现在有哈希值!
dwwilson66

1
这是一个很好的工具。
杰伊·基林

1
您可以将cutoff参数化和可选参数设置为默认值,方法是将其移至“函数”参数列表,Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) 然后删除函数内的声明。
核心

9

我不太关心冲突,但是需要基于可变长度字符串字段的弱伪随机行。这是一个有效的疯狂解决方案:

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

Z2包含要散列的字符串的单元格在哪里。

那里有“ MOD”,以防止溢出到科学计数法中。1009是素数,可以使用任何X,使得X * 255 < max_int_size。10是任意的;使用任何东西。“ else”值是任意的(pi的数字在这里!);使用任何东西。字符(1、3、5、7、9)的位置是任意的;使用任何东西。


2
老实说,这是最简单的答案,我怀疑冲突对于大多数excel用例都是一个问题。
轧辊

3

对于一个相当小的列表,您可以使用内置的Excel函数创建一个加扰器(穷人的哈希函数)。

例如

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

在此,A1和B1保留随机的起始字母和字符串长度。

稍微摆弄和检查,在大多数情况下,您可以很快获得可行的唯一ID。

工作原理:该公式使用字符串的第一个字母和取自字符串中间的固定字母,并将LEN()用作“扇形函数”以减少发生碰撞的机会。

CAVEAT:这不是一个哈希,但是当您需要快速完成某项工作并可以检查结果以查看没有冲突时,它会很好地工作。

编辑: 如果您的字符串应具有可变的长度(例如全名),但是是从具有固定宽度字段的数据库记录中提取的,则您需要这样做:

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

这样长度才是有意义的加扰器。


1
好答案!(:“穷人的哈希函数”,“ caveat”,“工作原理” :)
关于natty的细节

1
“检查结果以确保没有冲突”,您可以简单地通过运行DATA> REMOVE DUPLICATES进行尝试/测试,并查看是否存在冲突。[显然/大概,如果您确实进行重复操作,则可以迭代地重新运行上述功能,直到没有重复出现为止]
内容

2

我正在使用它,它在防止冲突的情况下提供了很好的结果,而无需每次都运行脚本。我需要一个介于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)))

它从字符串中选择字母,取每个字母的值,添加一个值(以防止相同的字母在不同的位置给出相同的结果),将每个值相乘/相除并在总数上运行COS函数。


1

你可以试试看 在两列上运行Pseudo#:

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

其中A1和B1存储手动输入的随机种子:0


0

据我所知,Excel中没有内置哈希函数-您需要在VBA中将其构建为用户定义函数。

但是,请注意,出于您的目的,我认为使用哈希不是必需的,也不是真正有用的方法!VLOOKUP在256个字节上的效果与在较小的散列上一样好。当然,它可能会稍微慢一点-可以肯定的是,它是如此之小以至于无法测量。然后添加哈希值将为您和Excel付出更多的努力。


是的...我知道,但是仅从演示的角度来看,我宁愿title在冻结的左窗格中显示15个字节的散列,即256个字节的散列...
dwwilson66 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.