我试图在一个文件中寻找一个标记':path,'然后将所有以下(任意数字计数)数字作为一个数字读取(因此对于':path,123'我寻找,在文件中然后读取整数123)。然后读取当前搜索位置和pos + 123之间的字符(将它们存储在列表或其他内容中)。然后寻找':path'的下一场比赛,然后重复这个过程。
我想要一个功能有点像:
def fregseek(FILE, current_seek, /regex/): . . value_found = ? # result of reading next N chars after :path,[0-9]+ . . return next_start_seek, value_found
一行中':path'可能有任意数量的匹配,并且该字符串可能出现在','之后指定的字符数内。我写了一堆乱七八糟的垃圾,每行写入,然后对于匹配所指示的前N个字符的每一行选择,然后继续处理字符串,直到它全部被吃掉。然后读取下一个字符串,依此类推。
这太可怕了,我不想从一个潜在的巨大文件中剔除所有线路,而我真正需要做的就是搜索(特别是因为换行是无关紧要的,因此需要额外的处理步骤只是因为行容易从文件中提取是荒谬的。)
所以,就是这样,我想解决的是我的问题。我需要寻找匹配,读取值,从该值的末尾继续寻找下一个匹配,依此类推,直到文件耗尽。
如果有人可以帮助我,我将很高兴收到他们的来信:)
我想尽可能避免使用非标准库,我也想要最短的代码,但这是我最不关心的问题(速度和内存消耗是重要的因素,但我不希望50 loc额外的用一个小函数来引导一些库,只要我知道它是什么就可以撕掉它。
我更喜欢python代码,但是,如果perl在这方面打败了python,我将使用perl,我也会对聪明的sed / awk / bash脚本等开放,只要它们的速度不是很慢。
非常感谢。
答案 0 :(得分:3)
如果您不需要正则表达式,只需查找和切片即可完成此操作。
无论哪种方式,简单的解决方案是将整个文件读入内存,并查找并切片生成的str
/ bytes
对象。
但如果您不能(或不想)将整个文件读入内存,那么这不起作用。
幸运的是,如果您可以指望您的文件是<< 2GB或者你只需要在64位Python中工作,并且你在一个合理的平台(POSIX,现代Windows等)上,你可以mmap
将文件放入内存中。 mmap
对象具有字符串所具有的相同方法的子集,因此您可以假装您有一个字符串,就像您将整个文件读入内存一样,但您可以依赖Python实现和操作系统让它以合理的效率工作。
根据您的Python版本,re
可能无法扫描mmap,就像它是一个字符串一样,它可能会工作但速度很慢,或者它可能正常工作。所以,你最好先尝试一下,如果没有抛出异常或者比预期慢得多,你就完成了:
def findpaths(fname):
with open(fname, 'rb') as f:
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
for match in re.finditer(':path,([0-9]+)', m):
yield m[match.end():match.end()+int(match.group(1))]
(这与BrtH的答案相同,只是使用mmap而不是字符串,并重新构建为生成器而不是列表 - 尽管你当然可以通过用括号替换方括号来完成后一部分。)
如果你使用的是旧的(或非CPython?)版本的Python,它不能(有效地)re
mmap
,那就有点复杂了:
def nextdigits(s, start):
return ''.join(itertools.takewhile(str.isdigit,
itertools.islice(s, start, None)))
def findpaths(fname):
with open(fname, 'rb') as f:
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
i = 0
while True:
n = m.find(':path', i)
if n == -1: return
countstr = nextdigits(m, n+6)
count = int(countstr)
n += 6 + len(countstr)
yield m[n:n+count]
i = n + 6 + count
这可能不是编写nextdigits
函数的最快方法。我不确定这实际上是重要的(时间和时间),但如果确实如此,其他可能性是切出m[n+6:n+A_BIG_ENOUGH_NUMBER]
和正则表达式,或编写自定义循环,或者...另一方面,如果这是你的瓶颈,通过使用JIT(PyPy,Jython或IronPython)切换到解释器可能会获得更多好处......
对于我的测试,我将事情分开:findpaths
采用类似字符串的对象,调用者执行with open
和mmap
位并将m
传递给findpaths
;我这里不是为了简洁而做到的。
无论如何,我已根据以下数据测试了两个版本:
BLAH:path,3abcBLAH:path,10abcdefghijklmnBLAH:path,3abc:path,0:path,3abc
输出结果为:
abc
abcdefghij
abc
abc
我认为这是对的吗?
如果我的早期版本导致它在100%CPU下旋转,我的猜测是我没有在循环中正确增加i
;这是在紧密的解析循环中获得该行为的最常见原因。无论如何,如果您可以使用当前版本重现,请发布数据。
答案 1 :(得分:2)
你可以在python的近一行中完成:
with open('filename.txt') as f:
text = f.read()
results = [text[i[0]:i[0] + i[1]] for i in
((m.end(), int(m.group(1))) for m in
re.finditer(':path,([0-9]+)', text))]
注意:未经测试......