2 回答

TA貢獻1843條經驗 獲得超7個贊
您的代碼中有一些誤解,并且效率低下。讓我們從誤解開始。
由于firm.ori以二進制模式 ( rb)打開,因此結果s = f.read()是一個bytes對象。盡管具有與字符串類似的方法,但這不是字符串!它包含字節,而不是字符。當您顯示它時,\x...輸出不指示bytes包含 ASCII 反斜杠和 xes的對象。相反,每個\x...都是一個轉義序列,用于表示與 ASCII 可打印字符不對應的給定字節的十六進制值。
在您的循環中,您專門處理字符串:hexstr = '\\x'.join('{:02x}'.format(x) for x in i)采用您的排列并將其格式化為看起來像一個bytes對象的字符串表示。希望您從上一段中了解為什么這行不通。
s.find(b'hexstrfinal')搜索文字 ASCII 數組b'hexstrfinal',而不是名為 的變量hexstrfinal。后者當然不起作用,因為hexstrfinal有 type str,而不是bytes. 如果您要將其轉換為bytes使用簡單的hexstrfinal.encode('ascii'),則會得到b'\\x...',這根本不是您想要的。正確的方法是
s.find(hexstrfinal.encode('ascii').decode('unicode-escape').encode('latin1'))
希望您能明白為什么將字符串轉換三次以獲得所需的效率會不必要地低下bytes。任何時候您開始使用字符串作為操縱數字的拐杖時,都是評估您的方法的好時機。這開始了我們對代碼效率低下的討論。
您目前正在嘗試遍歷 0-7 的所有可能排列,而不是尋找實際存在的排列。鑒于該文件只有 200KB 大小,期望所有甚至大部分排列都出現在其中是不合理的。此外,您正在為每個可能的排列搜索整個文件。對于文件大小N和K排列,您的代碼會O(N * K)及時運行,而可以在一次通過文件或O(N). 使用適當的數據結構,即使是用純 Python 編寫的循環也可能比當前代碼的優化版本運行得更快。
策略很簡單。遍歷s. 如果當前字符和以下七個字符構成有效排列,則開始聚會。否則,繼續尋找:
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}')
這里有許多可能的優化,你可以用 numpy 或 scipy 更有效地完成整個事情。
如果您允許在序列中重復,事情也會變得更加復雜。在這種情況下,您必須對序列進行排序:
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}')
如果您要搜索小吃,事情會變得更加復雜。我會完全放棄 check b in allowed,只寫一個可以在每半步應用的自定義檢查:
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')
在這里,build_set只是將半字節分成一組。matches檢查一個字節對齊的 8 個半字節數組(4 個元素),或偏移半字節(5 個元素)的 8 個半字節數組。這兩個案例都是獨立報告的。

TA貢獻1815條經驗 獲得超13個贊
目前尚不清楚您要搜索的內容,但是...
的每個排列(0,1,2,3,4,5,6,7)將是一個與此類似的七項元組
t = (7, 6, 4, 1, 3, 5, 0, 2)
你可以像這樣制作兩個項目的字符串
>>> a = [''.join(map(str,thing)) for thing in zip(t,t[1:])]
>>> a
['76', '64', '41', '13', '35', '50', '02']
然后制作字符串的整數并將其提供給 bytes
>>> b = bytes(map(int,a))
>>> b
b'L@)\r#2\x02'
然后搜索一下
>>> b in s
????
如果它沒有找到它就不存在。
這是一個十個字符的字節對象(類似于您的文件)
>>> b = b'\xcbl\x7f|_k\x00\x9f\xa2\xcc'
它恰好是:
>>> bytes([203, 108, 127, 124, 95, 107, 0, 159, 162, 204])
搜索3 個字符(或 3 個整數)序列
>>> bytes([127,94,107]) in b
False
>>> bytes([127,95,107]) in b
False
>>> bytes([124,95,107]) in b
True
>>>
當我處理二進制文件時,我真的認為整數而不是字符。
添加回答
舉報