我正在处理许多由文档名称作为关键字的数据列表。文档名称虽然具有很强的描述性,但是如果我需要查看它们,则会非常麻烦(最多256个字节是不动产),而且我希望能够创建一个较小的键字段,以便在需要时可以轻松重现做一个VLOOKUP
从另一个workseet或工作簿。
我认为标题中的哈希对于每个标题而言都是唯一且可复制的,将是最合适的。是否有可用的功能,或者我正在考虑开发自己的算法?
对这个或其他策略有什么想法或想法吗?
我正在处理许多由文档名称作为关键字的数据列表。文档名称虽然具有很强的描述性,但是如果我需要查看它们,则会非常麻烦(最多256个字节是不动产),而且我希望能够创建一个较小的键字段,以便在需要时可以轻松重现做一个VLOOKUP
从另一个workseet或工作簿。
我认为标题中的哈希对于每个标题而言都是唯一且可复制的,将是最合适的。是否有可用的功能,或者我正在考虑开发自己的算法?
对这个或其他策略有什么想法或想法吗?
Answers:
您无需编写自己的函数-其他人已经为您完成了此任务。
例如,我在此stackoverflow答案中收集并比较了五个VBA哈希函数
我个人使用此VBA功能
=BASE64SHA1(A1)
将宏复制到VBA 模块后,在Excel中调用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
自定义哈希长度
Const cutoff As Integer = 5
还有一些哈希函数(所有三个CRC16函数)都不需要.NET且不使用外部库。但是哈希更长,并且产生更多的冲突。
您也可以只下载此示例工作簿并试用所有5种哈希实现。如您所见,第一张纸上有一个很好的比较
cutoff
参数化和可选参数设置为默认值,方法是将其移至“函数”参数列表,Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8)
然后删除函数内的声明。
我不太关心冲突,但是需要基于可变长度字符串字段的弱伪随机行。这是一个有效的疯狂解决方案:
=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)的位置是任意的;使用任何东西。
对于一个相当小的列表,您可以使用内置的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))
这样长度才是有意义的加扰器。
我正在使用它,它在防止冲突的情况下提供了很好的结果,而无需每次都运行脚本。我需要一个介于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函数。
据我所知,Excel中没有内置哈希函数-您需要在VBA中将其构建为用户定义函数。
但是,请注意,出于您的目的,我认为使用哈希不是必需的,也不是真正有用的方法!VLOOKUP
在256个字节上的效果与在较小的散列上一样好。当然,它可能会稍微慢一点-可以肯定的是,它是如此之小以至于无法测量。然后添加哈希值将为您和Excel付出更多的努力。
title
在冻结的左窗格中显示15个字节的散列,即256个字节的散列...
#NAME?
。查看代码>剪切代码并将其粘贴到新窗口中-在导航器中的正确工作表中>另存为启用了宏的工作表>关闭并返回到excel ...还有其他我想念的东西吗?我需要以某种方式进行编译吗?