使用Bash还是Python从文本文件中提取块
我有一个很大的文本文件,它的结构是这样的:
SEPARATOR
STRING1
(arbitrary number of lines)
SEPARATOR
...
SEPARATOR
STRING2
(arbitrary number of lines)
SEPARATOR
SEPARATOR
STRING3
(arbitrary number of lines)
SEPARATOR
....
文件中不同“块”之间唯一变化的就是STRING和分隔符之间的内容。我需要一个用bash或python写的脚本,给定一个输入STRING_i,输出一个文件,里面包含
SEPARATOR
STRING_i
(number of lines for this string)
SEPARATOR
在这里使用bash还是python,哪个方法更好?还有其他选择吗?这个过程也必须要快。
谢谢
4 个回答
0
如果你想让这个过程快一点,就得避免一次性读取整个文件来找到你需要的数据块。
- 先把文件读一遍,记录下每个STRING_I的起始位置(字节偏移量)和到下一个分隔符的距离(字节数)。你可以把这些记录放在一个单独的文件里,或者放在当前文件的“头部”。
- 每次查询STRING_I时,就读取这个记录。
if STRING_I in index: file.seek( start_byte_location ) file.read( length ) return parse_with_any_of_procedures_above # like @gruszczy's doit() but w/o loop
不要把索引做得太复杂:用一个字典来表示STRING_I和它的位置、长度的关系,然后把这个字典用simplejson或pickle保存到文件里。
0
我会用Python写一些类似这样的代码:
import sys
file = open("file", "r")
counter = 0
count = False
for line in file:
if count:
counter += 1
if count and SEPARATOR == line:
break
if not count and sys.argv[1] == line:
count = True
print SEPARATOR, sys.argv[1], counter, SEPARATOR
file.close()
3
在Python 2.6或更高版本中:
def doit(inf, ouf, thestring, separator='SEPARATOR\n'):
thestring += '\n'
for line in inf:
# here we're always at the start-of-block separator
assert line == separator
blockid = next(inf)
if blockid == thestring:
# found block of interest, use enumerate to count its lines
for c, line in enumerate(inf):
if line == separator: break
assert line == separator
# emit results and terminate function
ouf.writelines((separator, thestring, '(%d)' % c, separator))
inf.close()
ouf.close()
return
# non-interesting block, just skip it
for line in inf:
if line == separator: break
在旧版本的Python中,你几乎可以做到同样的事情,但需要把这一行 blockid = next(inf)
改成 blockid = inf.next()
。
这里的假设是输入和输出文件是由调用者打开的(调用者还会传入有用的值,比如 thestring
,以及可选的 separator
),但这个函数的工作是关闭这些文件(例如,为了方便作为管道过滤器使用,输入是 sys.stdin
,输出是 sys.stdout
);当然,如果需要的话,这部分可以很容易地调整。
去掉 assert
语句会让程序运行得稍微快一点,但我喜欢它们的“合理性检查”作用(而且它们也有助于理解代码的逻辑流程)。
这个方法的关键在于文件是一个迭代器(按行读取),而迭代器可以在多个地方前进(所以我们可以有多个 for
循环,或者特定的“前进迭代器”的调用,比如 next(inf)
,它们能够很好地配合工作)。