在 Python 中迭代 n 嵌套 for 循环的更有效方法
More efficient way to iterate through n-nested for loops in Python
我目前正在开发一个“去散列”脚本,它允许用户输入一个输入,连同散列方法,该脚本遍历字符列表,构建不同长度的字符串,并尝试检查如果任何字符组合(长度为 1-8)经过散列后等于用户提供的输入。
例如用户提供'password'的散列版本,算法取所有可能,从长度1开始:
长度 1: a, b, c, d, ..., z
长度 2: aa, ab, ac, ..., zz
长度 3: aaa, aab, aac, ..., zzz
依此类推,直到达到长度8(包括它)。
它会逐一散列所有可能性,并检查它们是否等于用户的输入。如果是,程序输出未散列的字符串并停止搜索。
我首先考虑对长度 1 使用 1 个 for()
循环,对长度 2 使用 2 个嵌套 for()
循环,依此类推,但认为我可能会复制和粘贴太多相同的内容代码,所以我用谷歌搜索了一些其他选项,我发现我可以使用 itertools.
这就是我生成 n 嵌套 for()
循环的方式:
chars = "abcdefghijklmnopqrstuvwxyz"
ranges = []
for i in range(0, length):
ranges.append(range(0, len(chars)))
for xs in itertools.product(*ranges):
# build the string here, hash it and check if it maches the user's input
我没有提供完整的实现,因为不仅仅是检查(如果找到什么就写入文件,输出东西等等)。
这个想法是,我意识到这个算法对于长度 1-4 工作得很好。长度为 1、2 或 3 的字符串可在不到一秒内找到,而长度为 4 的字符串也可能需要几分钟。
我还“改进”了搜索,使用 multiprocessing
并在每个进程中搜索两个长度的组。
问题是,该算法仍然效率不够。例如,如果我想搜索长度为 5 的字符串,我将不得不等待几个小时,而且我很确定这是实现我实际所做的更有效的方法。
还测试了 n 嵌套正常 for()
循环与这种类型的 itertool 实现的执行时间,发现 for()
循环快 2 倍。不应该正好相反吗?
你对如何改进我的算法有什么建议吗?
您可以直接使用 chars
作为 itertools.product
的可迭代对象。此外,product
接受一个可选参数 repeat
如果您想要一个可迭代对象与其自身的乘积。参考the documentation.
product
生成元组。要从字符串元组中获取字符串,请使用 ''.join()
.
from itertools import product
def find_password(hashed, length, chars = "abcdefghijklmnopqrstuvwxyz"):
for p in product(chars, repeat=length):
if hash(''.join(p)) == hashed:
return ''.join(p)
return None
password = 'aaabc'
print( find_password(hash(password), len(password)) )
# aaabc
此外,您可以使用 from string import ascii_lowercase
而不是硬编码您自己的字母表:
from string import ascii_lowercase
print(ascii_lowercase)
# abcdefghijklmnopqrstuvwxyz
我目前正在开发一个“去散列”脚本,它允许用户输入一个输入,连同散列方法,该脚本遍历字符列表,构建不同长度的字符串,并尝试检查如果任何字符组合(长度为 1-8)经过散列后等于用户提供的输入。
例如用户提供'password'的散列版本,算法取所有可能,从长度1开始:
长度 1: a, b, c, d, ..., z
长度 2: aa, ab, ac, ..., zz
长度 3: aaa, aab, aac, ..., zzz
依此类推,直到达到长度8(包括它)。
它会逐一散列所有可能性,并检查它们是否等于用户的输入。如果是,程序输出未散列的字符串并停止搜索。
我首先考虑对长度 1 使用 1 个 for()
循环,对长度 2 使用 2 个嵌套 for()
循环,依此类推,但认为我可能会复制和粘贴太多相同的内容代码,所以我用谷歌搜索了一些其他选项,我发现我可以使用 itertools.
这就是我生成 n 嵌套 for()
循环的方式:
chars = "abcdefghijklmnopqrstuvwxyz"
ranges = []
for i in range(0, length):
ranges.append(range(0, len(chars)))
for xs in itertools.product(*ranges):
# build the string here, hash it and check if it maches the user's input
我没有提供完整的实现,因为不仅仅是检查(如果找到什么就写入文件,输出东西等等)。 这个想法是,我意识到这个算法对于长度 1-4 工作得很好。长度为 1、2 或 3 的字符串可在不到一秒内找到,而长度为 4 的字符串也可能需要几分钟。
我还“改进”了搜索,使用 multiprocessing
并在每个进程中搜索两个长度的组。
问题是,该算法仍然效率不够。例如,如果我想搜索长度为 5 的字符串,我将不得不等待几个小时,而且我很确定这是实现我实际所做的更有效的方法。
还测试了 n 嵌套正常 for()
循环与这种类型的 itertool 实现的执行时间,发现 for()
循环快 2 倍。不应该正好相反吗?
你对如何改进我的算法有什么建议吗?
您可以直接使用 chars
作为 itertools.product
的可迭代对象。此外,product
接受一个可选参数 repeat
如果您想要一个可迭代对象与其自身的乘积。参考the documentation.
product
生成元组。要从字符串元组中获取字符串,请使用 ''.join()
.
from itertools import product
def find_password(hashed, length, chars = "abcdefghijklmnopqrstuvwxyz"):
for p in product(chars, repeat=length):
if hash(''.join(p)) == hashed:
return ''.join(p)
return None
password = 'aaabc'
print( find_password(hash(password), len(password)) )
# aaabc
此外,您可以使用 from string import ascii_lowercase
而不是硬编码您自己的字母表:
from string import ascii_lowercase
print(ascii_lowercase)
# abcdefghijklmnopqrstuvwxyz