代码之家  ›  专栏  ›  技术社区  ›  Christian Hayter

在VB6中散列这种复杂结构的最佳方法是什么?

  •  0
  • Christian Hayter  · 技术社区  · 15 年前

    我定义了以下结构(名称是匿名的,但数据类型是正确的):

    Public Type ExampleDataItem
        Limit As Integer    ' could be any value 0-999
        Status As Integer   ' could be any value 0-2
        ValidUntil As Date  ' always a valid date
    End Type
    
    Public Type ExampleData
        Name As String      ' could be 5-20 chars long
        ValidOn As Date     ' could be valid date or 1899-12-30 representing "null"
        Salt As Integer     ' random value 42-32767
        Items(0 To 13) As ExampleDataItem
    End Type
    

    我想为 ExampleData 实例。最小化哈希冲突很重要,性能和数据顺序不重要。

    到目前为止,我得到(伪代码):

    1. 将所有成员序列化为一个字节数组。
    2. 循环通过字节数组,一次读取4个字节到 Long 价值。
    3. 异或全部 价值观在一起。

    我不能真正发布我的代码,因为它很大程度上依赖于实用程序类来进行序列化,但是如果有人想看到它,不管怎样,我都会发布它。

    这样可以吗,或者有人能建议更好的方法吗?

    编辑:

    此代码正用于实现部分软件许可系统。散列的目的是确认最终用户输入的数据是否等于技术支持人员输入的数据。因此哈希必须:

    1. 很矮。这就是为什么我认为32位是最合适的,因为它可以在屏幕上呈现为10位十进制数字。这很容易,快速和明确的阅读电话和输入。
    2. 来源于 全部的 数据结构中的字段,没有额外的人工键或任何其他诡计。

    查找、唯一性测试或存储不需要哈希 示例数据 任何类型集合中的实例,但仅用于上述一个目的。

    4 回复  |  直到 15 年前
        1
  •  3
  •   MarkJ    15 年前

    你能用CRC32吗?史蒂夫麦克马洪 an implementation . 再加上一点 base32 编码,你有足够短的时间来阅读电话。

        2
  •  0
  •   PaulG    15 年前

    你可能想得太多了,或者我不理解这个问题。您基本上可以只是散列(cstr(salt)+name+cstr(validon)+任何其他字符串)。

    没有特别需要经历序列化为字节数组和异或值的过程。事实上,以这种方式将值交叉在一起更有可能在不需要的地方创建哈希冲突。

    编辑: 我想我现在明白了。您是通过将数据异化来创建自己的哈希值的?不幸的是,很可能发生碰撞。我知道vb6不包括任何哈希算法,所以您最好导入和使用类似的 Phil Fresle's SHA256 implementation .

        3
  •  0
  •   RS Conley    15 年前

    考虑到性能不是一个目标,如果文件大小不重要,并且您希望每个项目都有一个唯一的值。只需添加一个ID字段。它的数据类型是字符串。然后使用此函数生成一个guid。这将是一个唯一的ID。将其用作听写或集合的键。

    Public Type GUID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(7) As Byte
    End Type
    
    Public Type GUID2              '15 BYTES TOTAL
        Data1(14) As Byte
    End Type
    
    Public Declare Function CoCreateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long
    
    Public Function GetGUID() As String
        Dim VBRIG_PROC_ID_STRING As String
        VBRIG_PROC_ID_STRING = "GetGUID()"
    
        Dim lResult As Long
        Dim lguid As GUID
        Dim MyguidString As String
        Dim MyGuidString1 As String
        Dim MyGuidString2 As String
        Dim MyGuidString3 As String
        Dim DataLen As Integer
        Dim StringLen As Integer
        Dim i As Integer
        On Error GoTo error_olemsg
        lResult = CoCreateGuid(lguid)
        If lResult = 0 Then
            MyGuidString1 = Hex$(lguid.Data1)
            StringLen = Len(MyGuidString1)
            DataLen = Len(lguid.Data1)
            MyGuidString1 = LeadingZeros(2 * DataLen, StringLen) & MyGuidString1
            'First 4 bytes (8 hex digits)
            MyGuidString2 = Hex$(lguid.Data2)
            StringLen = Len(MyGuidString2)
            DataLen = Len(lguid.Data2)
            MyGuidString2 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString2)
            'Next 2 bytes (4 hex digits)
            MyGuidString3 = Hex$(lguid.Data3)
            StringLen = Len(MyGuidString3)
            DataLen = Len(lguid.Data3)
            MyGuidString3 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString3)
            'Next 2 bytes (4 hex digits)
            GetGUID = MyGuidString1 & MyGuidString2 & MyGuidString3
            For i = 0 To 7
                MyguidString = MyguidString & Format$(Hex$(lguid.Data4(i)), "00")
            Next i
            'MyGuidString contains last 8 bytes of Guid (16 hex digits)
            GetGUID = GetGUID & MyguidString
        Else
            GetGUID = "00000000" ' return zeros if function unsuccessful
        End If
        Exit Function
    error_olemsg:
        GetGUID = "00000000"
        Exit Function
    End Function
    
    Public Function LeadingZeros(ExpectedLen As Integer, ActualLen As Integer) As String
        LeadingZeros = String$(ExpectedLen - ActualLen, "0")
    End Function
    
        4
  •  0
  •   Community CDub    7 年前

    编辑: 这个问题现在已经被编辑,以澄清其目标是检测输入错误,而不是最小化完全不同值之间的冲突。在那种情况下 Dan F's answer 是最好的一个,但不是我下面的提议(尽管很好)。


    你可以用微软 CryptoAPI 而不是滚动您自己的哈希算法。

    • 例如 this 有关使用vb6中CryptoAPI的Microsoft文章应该可以开始了。
    • this 来自mvps.org上的edanmo,用于散列vb6中的字符串。

    编辑:以下注释。如果坚持使用32位值,则很难将哈希冲突最小化。我的 algorithm book 建议使用霍纳方法作为一个体面的通用哈希算法。我现在没有时间了解更多信息并在VB6中实现。 CopyMemory 可能有用:)