我正在将我的python应用程序从python 2转换为python 3.我使用的一个函数是从二进制文件中获取可打印字符。我之前在python 2中使用了以下函数,它运行得很好:
import string
def strings(filename, min=4):
with open(filename, "rb") as f:
result = ""
for c in f.read():
if c in string.printable:
result += c
continue
if len(result) >= min:
yield result
result = ""
if len(result) >= min: # catch result at EOF
yield result
代码实际上来自Python equivalent of unix "strings" utility。当我使用python 2运行上面的代码时,它产生这样的输出,这对我来说绝对没问题:
+s
^!1^
i*Q(
}"~
%lh!ghY
#dh!
!`,!
mL#H
o!<XXT0
' <
z !Uk
%
wS
n` !wl
*ty
(Q 6
!XPLO$
E#kF
然而,该函数在python 3下给出了奇怪的结果。它产生错误:
TypeError: 'in <string>' requires string as left operand, not int
所以我通过替换
将'int'转换为'str'if c in string.printable:
用这个
if str(c) in string.printable:
(我还转换了抛出相同错误消息的所有地方)
现在python 3提供了以下输出:
56700
0000000000000000000000000000000000000000
1236
60000
400234
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2340
0000
5010
5000
17889
2348
23400000000
5600
当我使用python 3时,我无法看到任何字符。任何有助于使代码工作或指向解决方案的帮助都表示赞赏。我需要的是从二进制文件中提取字符串(非常小,只有几个kb)并将其存储在变量中。
答案 0 :(得分:2)
在Python 3中,以二进制模式打开文件会为您提供bytes
个结果。对bytes
对象进行迭代可以得到整数,而不是字符,范围为0到255(含)。来自bytes
documentation:
虽然字节文字和表示基于ASCII文本,但
bytes
个对象实际上表现为不可变的整数序列,序列中的每个值都被限制为0 <= x < 256
将string.printable
转换为集合并对其进行测试:
printable = {ord(c) for c in string.printable}
和
if c in printable:
接下来,您希望附加到bytesarray()
对象以保持合理的性能,并从ASCII解码以产生str
结果:
printable = {ord(c) for c in string.printable}
with open(filename, "rb") as f:
result = bytearray()
for c in f.read():
if c in printable:
result.append(c)
continue
if len(result) >= min:
yield result.decode('ASCII')
result.clear()
if len(result) >= min: # catch result at EOF
yield result
不是逐个迭代字节,而是可以拆分不可打印的任何内容:
import re
nonprintable = re.compile(b'[^%s]+' % re.escape(string.printable.encode('ascii')))
with open(filename, "rb") as f:
for result in nonprintable.split(f.read()):
if result:
yield result.decode('ASCII')
我会探索在块中阅读文件,而不是一次性阅读;不要试图将大文件放入内存中:
with open(filename, "rb") as f:
buffer = b''
for chunk in iter(lambda: f.read(2048), b''):
splitresult = nonprintable.split(buffer + chunk)
buffer = splitresult.pop()
for string in splitresult:
if string:
yield string.decode('ascii')
if buffer:
yield buffer.decode('ascii')
缓冲区将任何不完整的单词从一个块转移到下一个块;如果输入分别以不可打印的字符开始或结束,re.split()
会在开头和结尾生成空值。
答案 1 :(得分:-1)
我相信这会奏效。
作为发电机:
import string, _io
def getPrintablesFromBinaryFile(path, encoding='cp1252'):
global _io, string
buffer = _io.BufferedReader(open(path, 'rb'))
while True:
byte = buffer.read(1)
if byte == b'':
return #EOF
try:
d = byte.decode(encoding)
except:
continue
if d in string.printable:
yield d
作为一个函数,只需将getPrintablesFromBinaryFile()的输出收集到一个iterable中。
说明:
'\xef'
不使用UTF-8进行解码) 注意: cp1252
是许多文本文件的编码