将您的字符串分成三个较短的字符串(如果不能被三整除,则最后一个字符串将比其他两个字符串长)。对每个字符串运行您的“简短”算法,然后将结果连接起来。
我可以编写代码,但基于问题的质量,我认为您可以从这里开始!
编辑:事实证明,那个建议还不够。您原始的CRC16代码存在严重缺陷,即该行代码:
j = Val("&H" + Mid(txt, nC, 2))
这只处理可以解释为十六进制值的文本:小写字母和大写字母相同,并且字母表中F之后的任何内容都将被忽略(据我所知)。真正好的结果出现了,这是一个奇迹。如果您用以下行替换原行
j = asc(mid(txt, nC, 1))
事情做得更好-每个ASCII码至少从一开始就是它自己的值。
将这个变化与我之前提出的建议结合起来,您将获得以下代码:
Function hash12(s As String)
' create a 12 character hash from string s
Dim l As Integer, l3 As Integer
Dim s1 As String, s2 As String, s3 As String
l = Len(s)
l3 = Int(l / 3)
s1 = Mid(s, 1, l3) ' first part
s2 = Mid(s, l3 + 1, l3) ' middle part
s3 = Mid(s, 2 * l3 + 1) ' the rest of the string...
hash12 = hash4(s1) + hash4(s2) + hash4(s3)
End Function
Function hash4(txt)
' copied from the example
Dim x As Long
Dim mask, i, j, nC, crc As Integer
Dim c As String
crc = &HFFFF
For nC = 1 To Len(txt)
j = Asc(Mid(txt, nC)) ' <<<<<<< new line of code - makes all the difference
' instead of j = Val("&H" + Mid(txt, nC, 2))
crc = crc Xor j
For j = 1 To 8
mask = 0
If crc / 2 <> Int(crc / 2) Then mask = &HA001
crc = Int(crc / 2) And &H7FFF: crc = crc Xor mask
Next j
Next nC
c = Hex$(crc)
' <<<<< new section: make sure returned string is always 4 characters long >>>>>
' pad to always have length 4:
While Len(c) < 4
c = "0" & c
Wend
hash4 = c
End Function
你可以在电子表格中放置此代码,例如
=hash12(“A2”)
等等。为了好玩,您还可以使用“新的、改进的”hash4算法,并查看它们之间的比较。我创建了一个数据透视表来计数冲突 - 对于
hash12
算法没有冲突,而
hash4
只有3个冲突。我相信你可以从中想出如何创建
hash8
等等。你问题中的“不需要唯一”意味着也许“改进”的
hash4
就是你所需要的。
原则上,四个字符的十六进制应该有64k个唯一值 - 因此两个随机字符串具有相同哈希的概率将是64k中的1个。当您有400个字符串时,有400 x 399/2个“可能的冲突对”~80k个机会(假设您拥有高度随机的字符串)。因此,在样本数据集中观察到三次冲突并不是不合理的分数。随着字符串数量N的增加,碰撞的概率会随着N的平方而增加。通过哈希12中的额外32位信息,您期望在N>大约20M时(插科打诨,头脑中的数学)看到碰撞。
您可以使哈希12代码更加紧凑,显然 - 并且应该很容易看出如何将其扩展到任意长度。
哦 - 最后一件事。如果您启用RC寻址,则使用
=CRC16(“string”)
作为电子表格公式会产生难以跟踪的
#REF
错误...这就是为什么我将其重命名为
hash4
的原因。