Python正则表达式用于MD5哈希

23

我想到了:

re.findall("([a-fA-F\d]*)", data)

但这种方法并不是很可靠,有没有更好的方法来获取所有MD5哈希代码?


2
你要防范哪种类型的傻瓜? - Greg Hewgill
在引号前加上 r:c = r"[a-fA-F\d]"; re.findall(r"(?<!%s)(?:%s){32}(?!%s)" % (c,)*3, data) - jfs
谢谢大家,我会添加长度的内容,这是我遇到问题的主要原因。以后也会使用'r'的方法,感谢您的提示! - Ashy
在我的注释中,(c,)*3 应该被替换为 (c,c,c) - jfs
6个回答

60

既然MD5只是由32个十六进制数字组成的字符串,那么你可以向你的表达式中添加一个检查"32位数字"的条件,类似于这样:

re.findall(r"([a-fA-F\d]{32})", data)

2
MD5不是全部小写吗?使用[0-9a-f]{32}会更好。 - enchance
3
维基百科上说:“在使用字母数字时,没有普遍的规定使用小写还是大写字母,每个社区标准或约定在特定环境中都有其流行或偏好。”为了保险起见,您应该覆盖所有情况。 - Tom Maier
1
虽然这个匹配符合MD5哈希,但它也匹配SHA1或SHA2哈希,或者说任何大于32的十六进制字符串。您应该通过要求数据具有开始和结束来完善您的正则表达式:^[a-fA-F\d]{32}$ - toringe
@TomMaier 如果你想让正则表达式更简洁,你也可以指定re.compile(r'[0-9a-f]{32}', re.IGNORECASE) - NuclearPeon

12

在使用Python中的正则表达式时,几乎总是应该使用原始字符串语法r"..."

re.findall(r"([a-fA-F\d]{32})", data)
这将确保字符串中的反斜杠不被正常的Python转义所解释,而是直接传递给re.findall函数,以便它可以按原样查看\d。在这种情况下,你很幸运\d没有被Python转义解释,但像\b这样的字符(在Python转义和正则表达式中具有完全不同的含义)就会产生问题。
更多信息请参见re模块文档

谢谢 Greg - 我编辑了我的答案,加入了 "r",最好不要引入微妙的错误! - Marc Novakowski

10

以下方法优于其他解决方案:

re.findall(r'(?i)(?<![a-z0-9])[a-f0-9]{32}(?![a-z0-9])', data)

这确保了匹配必须是一个由32个十六进制数字字符组成的字符串,但不包含在其他字母数字字符的更大字符串中。 对于所有其他解决方案,如果有37个连续的十六进制字符的字符串,该模式将匹配前32个字符并将其视为匹配项;或者如果有64个十六进制字符的字符串,则会将其分成两半并将每一半作为独立的匹配项。通过先行断言和后行断言来排除这些情况,它们是非捕获的,不会影响匹配结果的内容。

请注意,(?i)标志会使模式对大小写不敏感,这可以节省一点打字时间,而将整个模式用括号括起来是多余的。


2
为什么不直接添加^和$行锚定符,而要使用前瞻和后顾呢? - Imran
1
我假设他正在大量文本中搜索md5。如果您要检查单个字符串是否完全包含md5,则锚点是更好的方法。 - ʞɔıu

7

以下是一个相对严谨的表达:

r"\b([a-f\d]{32}|[A-F\d]{32})\b"
  • 字符串必须恰好为32个字符长,
  • 字符串必须位于单词边界之间(换行符、空格等),
  • 字母必须全部小写a-f或者全部大写A-F,但不可混合使用。

但是如果这还不够好,因为你知道得到全数字的MD5校验和的概率只有3402823分之一,获得全字母数字的MD5校验和的概率为42万亿分之一,那么我们应该对这些有效的校验和说FU,也不接受任何不是字母数字的内容:

r"\b(?!^[\d]*$)(?!^[a-fA-F]*$)([a-f\d]{32}|[A-F\d]{32})\b"

00000000000000000000000000000000 # not MD5
01110101001110011101011010101001 # not MD5
ffffffffffffffffffffffffffffffff # not MD5
A32efC32c79823a2123AA8cbDDd3231c # not MD5
affa687a87f8abe90d9b9eba09bdbacb # is MD5
C787AFE9D9E86A6A6C78ACE99CA778EE # is MD5
please like and subscribe to my  # not MD5

是的,我在工作中感到非常无聊。


1
只有在扫描单独的行时才有效。说实话,r"\b[a-f\d]{32}\b|\b[A-F\d]{32}\b" 更好。 - Adam Smith
1
很好 :)我想这完全取决于使用情况。你是想检查一个字符串是否类似于MD5,还是想从一个较大的字符串生成类似于MD5的字符串? :P - J.J
1
同意。我想象中的文件是一个MD5的列表,用逗号分隔而不是换行符。 - Adam Smith
我已经编辑了我的示例,包括单词分隔符,因为你显然是正确的,Adam :) - J.J

3

MD5 Python使用正则表达式的示例

由于MD5是由32个十六进制字符组成的,有时哈希值会用小写字母表示,因此还应考虑它们。


以下示例已针对四个不同的字符串进行测试:

  • 一个有效的小写MD5哈希值
  • 一个有效的大写MD5哈希值
  • 一个包含64个十六进制字符的字符串(以确保不会发生拆分和匹配)
  • 一个包含37个十六进制字符的字符串(以确保前32个字符不匹配)

900e3f2dd4efc9892793222d7a1cee4a

AC905DD4AB2038E5F7EABEAE792AC41B

900e3f2dd4efc9892793222d7a1cee4a900e3f2dd4efc9892793222d7a1cee4a

900e3f2dd4efc9892793222d7a1cee4a4a4a4


    validHash = re.finditer(r'(?=(\b[A-Fa-f0-9]{32}\b))', datahere)

    result = [match.group(1) for match in validHash]

    if result: 

        print "Valid MD5"

    else:

        print "NOT a Valid MD5"


2

那么对于需要32个字符的"([a-fA-F\d]{32})"怎么样?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接