我正在解析日志文件,其中包括有关许多作业的事件的行,这些行由作业ID标识。我正在尝试在Python中的两种模式之间获取日志文件中的所有行。
我已经阅读了这篇非常有用的帖子How to select lines between two patterns?,并且已经像这样解决了awk
的问题:
awk '/pattern1/,/pattern2/' file
由于我正在用Python脚本处理日志信息,因此我正在使用subprocess.Popen()
执行该awk命令。我的程序可以运行,但我想单独使用Python来解决。
我知道re
模块,但不太了解如何使用它。日志文件已经被压缩到bz2,所以这是我的代码,用于打开.bz2文件并查找两种模式之间的线:
import bz2
import re
logfile = '/some/log/file.bz2'
PATTERN = r"/{0}/,/{1}/".format('pattern1', 'pattern2')
# example: PATTERN = r"/0001.server;Considering job to run/,/0040;pbs_sched;Job;0001.server/"
re.compile(PATTERN)
with bz2.BZ2File(logfile) as fh:
match = re.findall(PATTERN, fh.read())
但是,match
为空(fh.read()
不是!)。使用re.findall(PATTERN, fh.read(), re.MULTILINE)
无效。
在re.DEBUG
之后使用re.compile()
会显示许多行,
literal 47
literal 50
literal 48
literal 49
literal 57
两个说
any None
我可以使用python print between two patterns, including lines containing patterns这样的循环来解决问题,但是我会尽量避免嵌套的for-if循环。我相信re
模块可以产生我想要的结果,但是我不是如何使用它的专家。
我正在使用Python 2.7.9。
答案 0 :(得分:1)
将整个日志文件读入内存通常不是一个好主意,因此我将为您提供逐行解决方案。我假设您的示例中的点是模式中唯一变化的部分。我还要假设您要在列表列表中收集线路组。
import bz2
import re
with_delimiting_lines = True
logfile = '/some/log/file.bz2'
group_start_regex = re.compile(r'/0001.server;Considering job to run/')
group_stop_regex = re.compile(r'/0040;pbs_sched;Job;0001.server/')
group_list = []
with bz2.BZ2File(logfile) if logfile.endswith('.bz2') else open(logfile) as fh:
inside_group = False
for line_with_nl in fh:
line = line_with_nl.rstrip()
if inside_group:
if group_stop_regex.match(line):
inside_group = False
if with_delimiting_lines:
group.append(line)
group_list.append(group)
else:
group.append(line)
elif group_start_regex.match(line):
inside_group = True
group = []
if with_delimiting_lines:
group.append(line)
请注意,match()
从行的开头开始匹配(就像在^
模式关闭的情况下,模式以re.MULTILINE
开头)
答案 1 :(得分:1)
/pattern1/,/pattern2/
不是正则表达式,而是特定于awk
的结构,该结构由两个正则表达式组成。
使用纯正则表达式,您可以将pattern1.*?pattern2
与DOTALL
标志一起使用(这会使.
在通常不匹配的情况下匹配换行符):
re.findall("pattern1.*?pattern2", input, re.DOTALL)
它不同于awk
命令,后者将匹配包含开始和结束模式的整行;这可以通过以下方式实现:
re.findall("[^\n]*pattern1.*?pattern2[^\n]*", input, re.DOTALL)
请注意,我回答您的问题是出于教学的考虑,但是Walter Tross' solution应该是首选。