<p>您的代码中存在一些误解,而且效率低下。让我们从误解开始。你知道吗</p>
<p>由于<code>firm.ori</code>是以二进制模式(<code>rb</code>)打开的,<code>s = f.read()</code>的结果是<code>bytes</code>对象。尽管有类似于字符串的方法,但这不是字符串!它包含字节,而不是字符。显示时,<code>\x...</code>输出并不表示<code>bytes</code>对象包含ASCII反斜杠和XE。相反,每个<code>\x...</code>是一个转义序列,用于表示与ASCII可打印字符不对应的给定字节的十六进制值。你知道吗</p>
<p>在循环中,您只处理字符串:<code>hexstr = '\\x'.join('{:02x}'.format(x) for x in i)</code>接受您的排列并将其格式化为<code>bytes</code>对象的字符串表示形式。希望你能从上一段理解为什么这行不通。你知道吗</p>
<p><code>s.find(b'hexstrfinal')</code>搜索文本ASCII数组<code>b'hexstrfinal'</code>,而不是名为<code>hexstrfinal</code>的变量。后者当然不起作用,因为<code>hexstrfinal</code>的类型是<code>str</code>,而不是<code>bytes</code>。如果用一个简单的<code>hexstrfinal.encode('ascii')</code>把它转换成<code>bytes</code>,你会得到<code>b'\\x...'</code>,这根本不是你想要的。正确的方法是</p>
<pre><code>s.find(hexstrfinal.encode('ascii').decode('unicode-escape').encode('latin1'))
</code></pre>
<p>希望您能理解为什么将一个字符串转换三次以获得所需的<code>bytes</code>是不必要的低效。任何时候,当你开始使用字符串作为拐杖来操纵数字时,都是评估你的方法的好时机。这就是我们开始讨论代码中的低效之处。你知道吗</p>
<p>您当前正在尝试遍历0-7的所有可能排列,而不是查找实际存在的排列。考虑到文件的大小只有200KB,期望所有甚至大多数排列都出现在文件中是不合理的。此外,您正在整个文件中搜索每个可能的排列。对于文件大小<code>N</code>和<code>K</code>排列,您的代码在<code>O(N * K)</code>时间内运行,而这可以通过文件的一次传递或<code>O(N)</code>完成。使用适当的数据结构,即使是用纯Python编写的循环也可能比当前代码的优化版本运行得更快。你知道吗</p>
<p>策略很简单。遍历<code>s</code>。如果当前字符和下面的七个字符组成了一个有效的排列,开始一个聚会。否则,请继续查看:</p>
<pre><code>N = 8
allowed = set(range(N))
for index, b in enumerate(s):
if b in allowed and set(s[index:index + N]) == allowed:
print(f'Found sequence {s[index:index + N]} at offset {index}')
</code></pre>
<p>这里有许多可能的优化,您可以使用numpy或scipy更有效地完成整个过程。你知道吗</p>
<p>如果你允许在序列中重复,事情也会变得更复杂。在这种情况下,您必须对序列进行排序:</p>
<pre><code>allowed = sorted(...)
N = len(allowed)
for index, b in enumerate(s):
if b in allowed and sorted(s[index:index + N]) == allowed:
print(f'Found sequence {s[index:index + N]} at offset {index}')
</code></pre>
<p>如果你想寻找一点点,事情会变得更复杂。我会完全放弃检查<code>b in allowed</code>,只需编写一个自定义检查,它可以应用于每半步:</p>
<pre><code>N = 8
def build_set(items):
output = set()
for b in items:
output.add(b & 0xF)
output.add((b >> 4) & 0xF)
return output
def matches(seq):
if len(seq) == N // 2:
return build_set(seq) == allowed
elif len(seq) == N // 2 + 1:
check = build_set(seq[1:-1])
check.add(seq[0] & 0xF)
check.add((seq[-1] >> 4) & 0xF)
return check == allowed
else:
return False
allowed = set(range())
for index, b in enumerate(s):
if matches(s[index:index + N // 2]):
print(f'Found sequence {s[index:index + N // 2]} at offset {index}.0')
if matches(s[index:index + N // 2 + 1]):
print(f'Found sequence {s[index:index + N // 2 + 1]]} at offset {index}.5')
</code></pre>
<p>在这里,<code>build_set</code>只是将小字节分成一组。<code>matches</code>检查在一个字节上对齐的8个半字节的数组(4个元素),或偏移半字节的8个半字节的数组(5个元素)。这两个病例都是独立报告的。你知道吗</p>