将你的字符串分成三个较短的字符串(如果不能被三整除,最后一个将比其他两个长)。在每个上运行你的“短”算法,并连接结果。
我可以编写代码,但根据问题的质量,我认为您可以从这里获取它!
编辑:事实证明,这个建议是不够的。您的原始 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
算法没有,只有 3 个hash4
. 我相信你可以弄清楚如何创建hash8
, ... 。您的问题中的“不需要独一无二”表明您可能hash4
只需要“改进”。
原则上,一个四字符的十六进制应该有 64k 的唯一值——所以两个随机字符串具有相同散列的机会是 64k 中的 1。当您有 400 个字符串时,有 400 x 399 / 2 个“可能的碰撞对”~ 80k 机会(假设您有高度随机的字符串)。因此,在样本数据集中观察三个碰撞并不是一个不合理的分数。随着字符串数量 N 的增加,发生冲突的概率为 N 的平方。使用 hash12 中额外的 32 位信息,您希望在 N > 20 M 左右时看到冲突(handwaving,in-my-头数学)。
很明显,你可以让 hash12 代码更紧凑一点——而且应该很容易看出如何将它扩展到任意长度。
哦,还有最后一件事。如果您启用了 RC 寻址,使用=CRC16("string")
电子表格公式会产生难以跟踪的#REF
错误......这就是我重命名它的原因hash4