ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 13961|回复: 15

[讨论] 32位MD5字符串转唯一数字

[复制链接]

TA的精华主题

TA的得分主题

发表于 2013-4-17 01:41 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:文本处理和正则
本帖最后由 liucqa 于 2013-4-17 03:05 编辑

MD5字符串形如(数字+大写字母,共32位):900150983CD24FB0D6963F7D28E17F72

下面的函数将这个32位的字符串转成两个数字,以便在大数据量做字符串索引的时候,会快些。
  1. Function Md5_Numeric(strMD5 As String)
  2.     Dim i&, j&, strMD5ANSI$, b() As Byte
  3.     Dim Numic1, Numic2, step

  4.     Numic1 = CDec(0)
  5.     Numic2 = CDec(0)
  6.     step = CDec(1)

  7.     strMD5ANSI = StrConv(Left(strMD5, 32), vbFromUnicode)
  8.     b = strMD5ANSI

  9.     For i = 0 To 15
  10.         If b(i) <= 57 Then
  11.             b(i) = b(i) - 48
  12.         Else
  13.             b(i) = b(i) - 65 + 10
  14.         End If
  15.         Numic1 = Numic1 + step * b(i)

  16.         j = i + 16
  17.         If b(j) <= 57 Then
  18.             b(j) = b(j) - 48
  19.         Else
  20.             b(j) = b(j) - 65 + 10
  21.         End If
  22.         Numic2 = Numic2 + step * b(j)
  23.         
  24.         step = step * 36         '因MD5字符串都是大写字母,所以b(i)最大是35
  25.     Next
  26.     Md52Numic = Numic1 & "," & Numic2
  27. End Function
复制代码
我测试了一下,一个Decimal 类型的数字,大约可以放17~18位字符串。所以32位字符串要拆成2个数字。


顺便说一下,返回值应该是个1维数组,存放两个数字。
我为了演示方便,改成字符串输出。

这个算法比直接转换成10进制数得到的数字要小些。







TA的精华主题

TA的得分主题

 楼主| 发表于 2013-4-17 02:32 | 显示全部楼层
36转10进制算法

  1. Function Convert36_10(n36 As String)
  2.     Dim basestr As String
  3.     Dim n
  4.     Dim i As Long
  5.     basestr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  6.     n36 = Left(n36, 16)
  7.     n = CDec(0)
  8.     For i = 1 To Len(n36)
  9.         n = n * 36 + (InStr(basestr, Mid(n36, i, 1)) - 1)
  10.     Next
  11.     Convert36_10 = n
  12. End Function
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-4-17 03:04 | 显示全部楼层
本帖最后由 liucqa 于 2013-4-17 22:59 编辑

优化了一下二楼的算法,发现还是进制转换的方法
  1. Sub test()
  2.     Dim md5$, MD5Val, MD5Val10
  3.     Dim t As Date, i&

  4.     md5 = GetMD5Hash_String("abc")

  5.     t = Timer
  6.     For i = 1 To 500000
  7.         MD5Val = Md5_Numeric(md5)
  8.     Next
  9.     MsgBox Format(Timer - t, "0.00")         '8.0

  10.     t = Timer
  11.     For i = 1 To 500000
  12.         MD5Val10 = Convert36_10(md5)
  13.     Next
  14.     MD5Val10 = Convert36_10(md5)
  15.     MsgBox Format(Timer - t, "0.00")         '7.6
  16. End Sub

  17. Function Md5_Numeric(strMD5 As String)

  18.     Dim i&, j&, b() As Byte
  19.     Dim Numic1, Numic2, step

  20.     Numic1 = CDec(0)
  21.     Numic2 = CDec(0)
  22.     step = CDec(1)

  23.     b = StrConv(Left(strMD5, 32), vbFromUnicode)

  24.     For i = 0 To 15
  25.         If b(i) <= 57 Then
  26.             b(i) = b(i) - 48
  27.         Else
  28.             b(i) = b(i) - 65 + 10
  29.         End If
  30.         Numic1 = Numic1 + step * b(i)

  31.         j = i + 16
  32.         If b(j) <= 57 Then
  33.             b(j) = b(j) - 48
  34.         Else
  35.             b(j) = b(j) - 65 + 10
  36.         End If
  37.         Numic2 = Numic2 + step * b(j)

  38.         step = step * 36         '因MD5字符串都是大写字母,所以b(i)最大是35
  39.     Next
  40.     Md5_Numeric = Numic1 & "," & Numic2
  41. End Function

  42. Function Convert36_10(n36 As String)
  43.     Dim basestr As String, b() As Byte
  44.     Dim i&, j&, Numic1, Numic2

  45.     b = StrConv(n36, vbFromUnicode)
  46.     Numic1 = CDec(0)
  47.     Numic2 = CDec(0)
  48.     For i = 0 To 15
  49.         If b(i) <= 57 Then
  50.             b(i) = b(i) - 48
  51.         Else
  52.             b(i) = b(i) - 65 + 10
  53.         End If
  54.         Numic1 = Numic1 * 36 + b(i)
  55.         j = i + 16
  56.         If b(j) <= 57 Then
  57.             b(j) = b(j) - 48
  58.         Else
  59.             b(j) = b(j) - 65 + 10
  60.         End If
  61.         Numic2 = Numic2 * 36 + b(j)
  62.     Next
  63.     Convert36_10 = Numic1 & "," & Numic2
  64. End Function
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-4-17 03:07 | 显示全部楼层
最后给出MD5的API程序
  1. Option Explicit
  2. Option Base 0

  3. Public Type MD5_CTX
  4.     i(1) As Long
  5.     buf(3) As Long
  6.     inc(63) As Byte
  7.     digest(15) As Byte
  8. End Type

  9. Public Declare Sub MD5Init Lib "Cryptdll.dll" (ByVal pContex As Long)
  10. Public Declare Sub MD5Final Lib "Cryptdll.dll" (ByVal pContex As Long)
  11. Public Declare Sub MD5Update Lib "Cryptdll.dll" (ByVal pContex As Long, ByVal lPtr As Long, ByVal nSize As Long)

  12. Public Function ConvBytesToBinaryString(bytesIn() As Byte) As String
  13.     Dim i As Long
  14.     Dim nSize As Long
  15.     Dim strRet As String

  16.     nSize = UBound(bytesIn)
  17.     For i = 0 To nSize
  18.         strRet = strRet & Right$("0" & Hex(bytesIn(i)), 2)
  19.     Next
  20.     ConvBytesToBinaryString = strRet
  21. End Function

  22. Public Function GetMD5Hash(bytesIn() As Byte) As Byte()
  23.     Dim ctx As MD5_CTX
  24.     Dim nSize As Long

  25.     nSize = UBound(bytesIn) + 1

  26.     MD5Init VarPtr(ctx)
  27.     MD5Update ByVal VarPtr(ctx), ByVal VarPtr(bytesIn(0)), nSize
  28.     MD5Final VarPtr(ctx)

  29.     GetMD5Hash = ctx.digest
  30. End Function

  31. Public Function GetMD5Hash_Bytes(bytesIn() As Byte) As String
  32.     GetMD5Hash_Bytes = ConvBytesToBinaryString(GetMD5Hash(bytesIn))
  33. End Function

  34. Public Function GetMD5Hash_String(ByVal strIn As String) As String
  35.     GetMD5Hash_String = GetMD5Hash_Bytes(StrConv(strIn, vbFromUnicode))
  36. End Function

  37. Public Function GetMD5Hash_File(ByVal strFile As String) As String
  38.     Dim lFile As Long
  39.     Dim bytes() As Byte
  40.     Dim lSize As Long

  41.     lSize = FileLen(strFile)
  42.     If (lSize) Then
  43.         lFile = FreeFile
  44.         ReDim bytes(lSize - 1)
  45.         Open strFile For Binary As lFile
  46.         Get lFile, , bytes
  47.         Close lFile
  48.         GetMD5Hash_File = GetMD5Hash_Bytes(bytes)
  49.     End If
  50. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2013-4-17 08:40 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
CDEC最大值是79,228,162,514,264,337,593,543,950,335
29位。

那么9999……取28位时,可以保证不产生溢出。即处理10^28以内的十进制整数没有问题。


TA的精华主题

TA的得分主题

发表于 2013-4-17 08:52 | 显示全部楼层
本帖最后由 香川群子 于 2013-4-21 18:58 编辑

呵呵,1楼函数Function Md5_Numeric(strMD5 As String) 的最后一句代码:

Md52Numic = Numic1 & "," & Numic2
这个应该是函数结果输出的语句吧。

但前面函数名称为 Md5_Numeric

产生了不一致,导致函数结果没有被输出。

点评

咋滴捏?哪错了?  发表于 2013-4-17 10:14

TA的精华主题

TA的得分主题

发表于 2013-4-17 09:02 | 显示全部楼层
MD5计算后返回的值就是四个Long类型的值。后面才被转换成16进制的字符串用来显示。你要数值的话直接取数组就好了,为什么还要多做一步转换呢?

TA的精华主题

TA的得分主题

发表于 2013-4-17 09:40 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
如果你是使用别的工具取到的MD5值字符串的话,直接转成4个Long是最简便的,直接
For I=0 To 3
   lngArr(I)=  Val("&H" & MID$("...",8* I +1,8)
Next I
直接就转出了四个长整型数据。

TA的精华主题

TA的得分主题

发表于 2013-4-17 09:59 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
liucqa 发表于 2013-4-17 03:04
优化了一下二楼的算法,发现还是二楼的快

md5 = GetMD5Hash_String("abc")

还少了Function GetMD5Hash_String() 的代码。

点评

防水墙老和我过不去,发现无数次,俺发的代码被删掉了  发表于 2013-4-17 10:15

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-4-17 10:12 | 显示全部楼层
本帖最后由 liucqa 于 2013-4-17 10:27 编辑
joforn 发表于 2013-4-17 09:40
如果你是使用别的工具取到的MD5值字符串的话,直接转成4个Long是最简便的,直接
For I=0 To 3
   lngArr ...

其实最终目的是把哈希值转成数字,做排序用。因为数字排序比字符串快得多。

如果是4个long,就得做4次排序。

要是能搞成1个数字就好了,百度半天,发现都是两个Int64数字。

有啥办法对长字符串做快速排序呢?100万行


您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-21 20:09 , Processed in 0.038508 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表