如何使用python在大文件中的两个模式之间进行grep

时间:2012-06-22 12:33:52

标签: python grep lines

我有一个非常大的文件,如下:

[PATTERN1]
line1
line2
line3 
...
...
[END PATTERN]
[PATTERN2]
line1 
line2
...
...
[END PATTERN]

我需要在另一个文件中提取变量启动器模式[PATTERN1]和另一个定义模式[END PATTERN]之间的行,仅用于某些特定的启动器模式。
例如:

[PATTERN2]
line1 
line2
...
...
[END PATTERN]

我已经使用此代码使用较小的文件执行相同的操作:

FILE=open('myfile').readlines()

newfile=[]
for n in name_list:
    A = FILE[[s for s,name in enumerate(FILE) if n in name][0]:]
    B = A[:[e+1 for e,end in enumerate(A) if 'END PATTERN' in end][0]]
    newfile.append(B)

其中'name_list'是一个包含我需要的特定启动器模式的列表。

有效!!但我想有一个更好的方法来处理大文件,而不使用.readlines()命令。
有人可以帮帮我吗?

非常感谢!

5 个答案:

答案 0 :(得分:2)

考虑:

# hi
# there
# begin
# need
# this
# stuff
# end
# skip
# this

with open(__file__) as fp:
    for line in iter(fp.readline, '# begin\n'):
        pass
    for line in iter(fp.readline, '# end\n'):
        print line

打印“需要这个东西”

更灵活(例如允许重新模式匹配)是使用itertools drop-andwhile:

with open(__file__) as fp:
    result = list(itertools.takewhile(lambda x: 'end' not in x, 
        itertools.dropwhile(lambda x: 'begin' not in x, fp)))

答案 1 :(得分:2)

使用类似

的内容
import re

START_PATTERN = '^START-PATTERN$'
END_PATTERN = '^END-PATTERN$'

with open('myfile') as file:
    match = False
    newfile = None

    for line in file:
        if re.match(START_PATTERN, line):
            match = True
            newfile = open('my_new_file.txt', 'w')
            continue
        elif re.match(END_PATTERN, line):
            match = False
            newfile.close()
            continue
        elif match:
            newfile.write(line)
            newfile.write('\n')

这将迭代文件而不将其全部读入内存。它还直接写入您的新文件,而不是附加到内存中的列表。如果您的来源足够大,也可能成为一个问题。

显然,您可能需要对此代码进行大量修改;也许正则表达式模式不需要匹配开始/结束行,在这种情况下用if 'xyz' in line替换它。

答案 2 :(得分:1)

我认为这与您的代码的作用相同:

FILE=open('myfile').readlines()

newfile=[]

pattern = None
for line in FILE:
    if line[0] == "[" and line[-1] == "]":
        pattern = line[1:-1]
        if pattern == "END PATTERN":
            pattern = None
        continue
    elif pattern is not None and pattern in name_list:
        newfile.append(line)

通过这种方式,您只需浏览一次所有行,然后随时填写您的列表。

答案 3 :(得分:1)

我是一个新的python程序员,所以我只是很难理解你的解决方案,但似乎有很多不必要的迭代正在进行。首先读入文件,然后为name_list中的每个项目迭代一次文件。此外,我不知道您是否打算稍后迭代newfile以实际将其写入文件。

这是我将如何做到这一点,虽然我意识到它不是最pythonic看起来的解决方案。你只会迭代一次文件。 (作为免责声明,我没有对此进行测试。)

patterns = {'startPattern1':"endPattern1", 'startPattern2':"endPattern2", 'startPattern3':"endPattern3"}

fileIn = open(filenameIn, 'r')
fileOut = open(filenameOut, 'w')
targetEndPattern = None

for line in fileIn:
   if targetEndPattern is not None:
       if line == targetEndPattern:
           targetEndPattern = None
       else:
           fileOut.write(line + "\n")
   elif line in patterns:
       targetEndPattern = patterns[line]

编辑:如果您期望按特定顺序排列模式,则必须修改此解决方案。我在假设模式的顺序无关紧要但每个开始模式与特定结束模式匹配的情况下编写了这个。

答案 4 :(得分:1)

我会使用基于生成器的解决方案

#!/usr/bin/env python    
start_patterns = ('PATTERN1', 'PATTERN2')
end_patterns = ('END PATTERN')

def section_with_bounds(gen):
  section_in_play = False
  for line in gen:
    if line.startswith(start_patterns):
      section_in_play = True
    if section_in_play:
      yield line
    if line.startswith(end_patterns):
      section_in_play = False

with open("text.t2") as f:
  gen = section_with_bounds(f)
  for line in gen:
    print line