用python从二进制文件中提取字符串

用python从二进制文件中提取字符串,python,string-search,Python,String Search,我有一个项目,其中给了我一个文件,我需要从文件中提取字符串。基本上可以考虑linux中的“strings”命令,但我是在python中这样做的。下一个条件是,文件作为流(例如字符串)提供给我,因此使用子流程函数之一运行字符串的明显答案也不是选项 我写了这段代码: def isStringChar(ch): if ord(ch) >= ord('a') and ord(ch) <= ord('z'): return True if ord(ch) >= ord('

我有一个项目,其中给了我一个文件,我需要从文件中提取字符串。基本上可以考虑linux中的“strings”命令,但我是在python中这样做的。下一个条件是,文件作为流(例如字符串)提供给我,因此使用子流程函数之一运行字符串的明显答案也不是选项

我写了这段代码:

def isStringChar(ch):
    if ord(ch) >= ord('a') and ord(ch) <= ord('z'): return True
    if ord(ch) >= ord('A') and ord(ch) <= ord('Z'): return True
    if ord(ch) >= ord('0') and ord(ch) <= ord('9'): return True

    if ch in ['/', '-', ':', '.', ',', '_', '$', '%', '\'', '(', ')', '[', ']', '<', '>', ' ']: return True

# default out
return False

def process(stream):
dwStreamLen = len(stream)
if dwStreamLen < 4: return None

dwIndex = 0;
strString = ''
for ch in stream:
    if isStringChar(ch) == False:
        if len(strString) > 4:
            #print strString
            strString = ''
    else:
        strString += ch
def isStringChar(ch):

如果ord(ch)>=ord('a')和ord(ch)=ord('a')和ord(ch)=ord('0')和ord(ch),那么至少有一个问题是您正在将整个流读入内存(
…=len(stream)
),另一个问题是您的
isStringChar
函数非常慢(函数调用相对较慢,并且您正在进行大量的调用)

最好是这样:

import sys
import string

printable = set(string.printable)

def process(stream):
    found_str = ""
    while True:
        data = stream.read(1024*4)
        if not data:
            break
        for char in data:
            if char in printable:
                found_str += char
            elif len(found_str) >= 4:
                yield found_str
                found_str = ""
            else:
                found_str = ""

 if __name__ == "__main__":
     for found_str in process(sys.stdin):
        print found_str
这将更快,因为:

  • “可打印字符”查找是通过一个集合查找(和O(1)操作)执行的,该操作直接调用(如果我没有弄错的话)C函数(这将非常快)
  • 流以4k块进行处理,这将提高内存使用率和大输入的运行时间,因为不需要交换

与David Wolever的速度相似,使用Python的正则表达式库
re
。优化的一个小故事是,编写的代码越少,速度就越快。循环库函数通常是用C实现的,它的速度比您希望的要快。set()中的
char(
比自己检查更快)也是如此。Python在这方面与C相反

import sys
import re

chars = r"A-Za-z0-9/\-:.,_$%'()[\]<> "
shortest_run = 4

regexp = '[%s]{%d,}' % (chars, shortest_run)
pattern = re.compile(regexp)

def process(stream):
    data = stream.read()
    return pattern.findall(data)

if __name__ == "__main__":
    for found_str in process(sys.stdin):
        print found_str
导入系统 进口稀土 chars=r“A-Za-z0-9/\-:,[u$%'()[\]” 最短运行时间=4 regexp='[%s]{%d,}%.(字符,最短运行) pattern=re.compile(regexp) def流程(流): data=stream.read() 返回模式.findall(数据) 如果名称=“\uuuuu main\uuuuuuuu”: 对于在处理中找到的字符串(sys.stdin): 打印找到

在4k块中工作会很聪明,但在使用
re
的边缘情况下会有点棘手。(其中两个字符位于4k块的末尾,下两个字符位于下一块的开头)

如果您可以读取C,可能会有所帮助。它只有几百行,所以也没那么糟糕。如果你还需要unicode字符串,那就是:你需要一个
或者:found_str=“”
。代码当前打印它偶然发现的任何4个可打印字符,不管它们是否在一行中。谢谢现在修好了。(如果这没有让它变得明显,我实际上还没有测试过这段代码…)这是一个很好的建议。我同意——对于较小的流(即,可以放入内存中的流),这当然更可取。我打赌你甚至可以把数据流分块,然后在不可打印的字符上分块运行这个正则表达式…嗯…@dougallj:这太快了。谢谢现在如果你也能找到unicode字符串,我会给你买杯啤酒;-)我不会(显然也没有)想到要用re来做这个。我能够在33秒内处理500毫克的测试文件。这完全在我的设计规范限制之内。@dougallj:使用re.escape()比将反斜杠硬编码到
chars
字符串中要好。您能按设置的字节数重叠这些块吗?