Python 我将如何解析以下日志?
我需要按以下格式解析日志:Python 我将如何解析以下日志?,python,parsing,Python,Parsing,我需要按以下格式解析日志: ===== Item 5483/14800 ===== This is the item title Info: some note ===== Item 5483/14800 (Update 1/3) ===== This is the item title Info: some other note ===== Item 5483/14800 (Update 2/3) ===== This is the item title Info: some more no
===== Item 5483/14800 =====
This is the item title
Info: some note
===== Item 5483/14800 (Update 1/3) =====
This is the item title
Info: some other note
===== Item 5483/14800 (Update 2/3) =====
This is the item title
Info: some more notes
===== Item 5483/14800 (Update 3/3) =====
This is the item title
Info: some other note
Test finished. Result Foo. Time 12 secunds.
Stats: CPU 0.5 MEM 5.3
===== Item 5484/14800 =====
This is this items title
Info: some note
Test finished. Result Bar. Time 4 secunds.
Stats: CPU 0.9 MEM 4.7
===== Item 5485/14800 =====
This is the title of this item
Info: some note
Test finished. Result FooBar. Time 7 secunds.
Stats: CPU 2.5 MEM 2.8
我只需要提取每个项目的标题(项目5484/14800之后的下一行)和结果。因此,我只需要保留带有项目标题和该标题结果的行,并放弃所有其他内容。
问题是,有时一个项目有注释(maxim 3),有时结果显示时没有附加注释,因此这使得它很棘手。
任何帮助都将不胜感激。我正在用python做解析器,但不需要实际的代码,但需要指出如何实现这一点 乐:我想要的结果是放弃所有其他东西,得到如下结果:
('This is the item title','Foo')
then
('This is this items title','Bar')
编辑:现在我看到了您要查找的结果,添加了更多内容。解析不是使用正则表达式完成的。如果您有一个结构合理的文本(看起来和您一样),您可以使用更快的测试(例如line.startswith()或类似的测试)。 字典列表似乎是此类键值对的合适数据类型。不知道还能告诉你什么。这似乎很琐碎
好的,在这种情况下,regexp方法更合适:
import re
re.findall("=\n(.*)\n", s)
比列表理解快
[item.split('\n', 1)[0] for item in s.split('=\n')]
以下是我得到的:
>>> len(s)
337000000
>>> test(get1, s) #list comprehensions
0:00:04.923529
>>> test(get2, s) #re.findall()
0:00:02.737103
吸取的教训。可能类似(log.log
是您的文件):
我建议启动一个循环来查找行中的“==”。让那把钥匙把你转到下一行的标题。设置一个查找结果的标志,如果在点击下一个“==”之前没有找到结果,则说没有结果。否则,用标题记录结果。重置您的标志并重复。您也可以将结果与标题一起存储在字典中,如果在标题和下一行“=”之间找不到结果,只需存储“无结果”
基于输出,这看起来非常简单。您可以尝试这样的方法(在类似c的伪代码中,因为我不懂python):
下面是一些不太好看的perl代码。也许你会发现它在某些方面很有用。快速破解,还有其他方法(我觉得这段代码需要防御)
#/usr/bin/perl-w
#
#$Id$
#
严格使用;
使用警告;
我的@ITEMS;
我的$item;
我的$state=0;
打开(FD,“{title}),die“似乎有什么不对劲,比抱歉更好安全。行$。:$Line\n”;
#如果我们有一个新的项目编号,请添加Previous项目并创建一个新项目。
如果($item_number!=$item->{item_number}){
推送(@ITEMS,$item);
$item={};
$item->{item_number}=$item_number;
}
}否则{
#第一项,没有项目。
$item={};#创建新项。
$item->{item_number}=$item_number;
}
$state=1;
}elsif($state==1){
die“数据必须以标题开头。”如果(不是$item);
#如果我们已经有了一个标题,请确保它匹配。
如果($item->{title}){
如果($item->{title}ne$行){
die“标题与项“.$item->{item_number}”不匹配,第$行:$line\n”;
}
}否则{
$item->{title}=$line;
}
$state++;
}elsif(($state==2)和($line=~/^Info:/)){
#只需确保对于状态2,我们有一行匹配信息。
$state++;
}elsif($state==3)和($line=~/^Test finished\.Result([^.]+)\.Time\d+secunds{0,1}.$/){
$item->{status}=$1;
$state++;
}elsif(($state==4)和($line=~/^Stats:/)){
$state++#统计数据之后,我们必须有一个新项目,否则我们将失败。
}否则{
die“无效数据,第$行:$行\n”;
}
}
#最后一项也需要注意。
推送(@ITEMS,$item)如果($item);
关闭FD;
#循环我们的项目并打印我们存储的信息。
对于$item(@ITEMS){
打印$item->{item_number}。”(“$item->{status}。”)“$item->{title}。”\n”;
}
我知道您并没有要求真正的代码,但对于基于生成器的文本模切器来说,这是一个非常好的机会:
# data is a multiline string containing your log, but this
# function could be easily rewritten to accept a file handle.
def get_stats(data):
title = ""
grab_title = False
for line in data.split('\n'):
if line.startswith("====="):
grab_title = True
elif grab_title:
grab_title = False
title = line
elif line.startswith("Test finished."):
start = line.index("Result") + 7
end = line.index("Time") - 2
yield (title, line[start:end])
for d in get_stats(data):
print d
# Returns:
# ('This is the item title', 'Foo')
# ('This is this items title', 'Bar')
# ('This is the title of this item', 'FooBar')
希望这足够简单。如果您对上述工作方式有任何疑问,请务必询问。带有组匹配的正则表达式在python中似乎可以完成这项工作:
import re
data = """===== Item 5483/14800 =====
This is the item title
Info: some note
===== Item 5483/14800 (Update 1/3) =====
This is the item title
Info: some other note
===== Item 5483/14800 (Update 2/3) =====
This is the item title
Info: some more notes
===== Item 5483/14800 (Update 3/3) =====
This is the item title
Info: some other note
Test finished. Result Foo. Time 12 secunds.
Stats: CPU 0.5 MEM 5.3
===== Item 5484/14800 =====
This is this items title
Info: some note
Test finished. Result Bar. Time 4 secunds.
Stats: CPU 0.9 MEM 4.7
===== Item 5485/14800 =====
This is the title of this item
Info: some note
Test finished. Result FooBar. Time 7 secunds.
Stats: CPU 2.5 MEM 2.8"""
p = re.compile("^=====[^=]*=====\n(.*)$\nInfo: .*\n.*Result ([^\.]*)\.",
re.MULTILINE)
for m in re.finditer(p, data):
print "title:", m.group(1), "result:", m.group(2)er code here
如果您需要有关正则表达式的更多信息,请检查:。这是maciejka解决方案的延续(请参见此处的注释)。如果数据在daniels.log文件中,那么我们可以使用itertools.groupby逐项检查它,并对每个项目应用多行regexp。这个比例应该很好
import itertools, re
p = re.compile("Result ([^.]*)\.", re.MULTILINE)
for sep, item in itertools.groupby(file('daniels.log'),
lambda x: x.startswith('===== Item ')):
if not sep:
title = item.next().strip()
m = p.search(''.join(item))
if m:
print (title, m.group(1))
如果能看到您希望看到的确切输出,那将非常有帮助。类似于[('Item 5483/14800','12')…]?grep-A1-E“^===^Test“$LOGFILE | grep-B2”Test finished“| grep-v--| sed-E”$!Ns/\n/'-e“s/测试完成。([^.]*)\..*/,\1/”使用GNU grep 2.2这是项目标题,结果Foo这是项目标题,结果栏这是项目标题,结果FooB+1。。。OP这样问:“任何帮助都将不胜感激。我正在用python做解析器,但不需要实际的代码,但有人指出我如何才能做到这一点?”幸好他不想要代码,我不知道python值多少钱:)多行代码使用得很好。唯一的问题是它的伸缩性不是很好(您需要立即将整个文件保存在内存中),如果他使用itertools.groupby来查看这些项目呢?这只是一个建议,而不是一个完整的解决方案。如果它读入缓冲区,直到遇到以'====
#!/usr/bin/perl -w
#
# $Id$
#
use strict;
use warnings;
my @ITEMS;
my $item;
my $state = 0;
open(FD, "< data.txt") or die "Failed to open file.";
while (my $line = <FD>) {
$line =~ s/(\r|\n)//g;
if ($line =~ /^===== Item (\d+)\/\d+/) {
my $item_number = $1;
if ($item) {
# Just to make sure we don't have two lines that seems to be a headline in a row.
# If we have an item but haven't set the title it means that there are two in a row that matches.
die "Something seems to be wrong, better safe than sorry. Line $. : $line\n" if (not $item->{title});
# If we have a new item number add previuos item and create a new.
if ($item_number != $item->{item_number}) {
push(@ITEMS, $item);
$item = {};
$item->{item_number} = $item_number;
}
} else {
# First entry, don't have an item.
$item = {}; # Create new item.
$item->{item_number} = $item_number;
}
$state = 1;
} elsif ($state == 1) {
die "Data must start with a headline." if (not $item);
# If we already have a title make sure it matches.
if ($item->{title}) {
if ($item->{title} ne $line) {
die "Title doesn't match for item " . $item->{item_number} . ", line $. : $line\n";
}
} else {
$item->{title} = $line;
}
$state++;
} elsif (($state == 2) && ($line =~ /^Info:/)) {
# Just make sure that for state 2 we have a line that match Info.
$state++;
} elsif (($state == 3) && ($line =~ /^Test finished\. Result ([^.]+)\. Time \d+ secunds{0,1}\.$/)) {
$item->{status} = $1;
$state++;
} elsif (($state == 4) && ($line =~ /^Stats:/)) {
$state++; # After Stats we must have a new item or we should fail.
} else {
die "Invalid data, line $.: $line\n";
}
}
# Need to take care of the last item too.
push(@ITEMS, $item) if ($item);
close FD;
# Loop our items and print the info we stored.
for $item (@ITEMS) {
print $item->{item_number} . " (" . $item->{status} . ") " . $item->{title} . "\n";
}
# data is a multiline string containing your log, but this
# function could be easily rewritten to accept a file handle.
def get_stats(data):
title = ""
grab_title = False
for line in data.split('\n'):
if line.startswith("====="):
grab_title = True
elif grab_title:
grab_title = False
title = line
elif line.startswith("Test finished."):
start = line.index("Result") + 7
end = line.index("Time") - 2
yield (title, line[start:end])
for d in get_stats(data):
print d
# Returns:
# ('This is the item title', 'Foo')
# ('This is this items title', 'Bar')
# ('This is the title of this item', 'FooBar')
import re
data = """===== Item 5483/14800 =====
This is the item title
Info: some note
===== Item 5483/14800 (Update 1/3) =====
This is the item title
Info: some other note
===== Item 5483/14800 (Update 2/3) =====
This is the item title
Info: some more notes
===== Item 5483/14800 (Update 3/3) =====
This is the item title
Info: some other note
Test finished. Result Foo. Time 12 secunds.
Stats: CPU 0.5 MEM 5.3
===== Item 5484/14800 =====
This is this items title
Info: some note
Test finished. Result Bar. Time 4 secunds.
Stats: CPU 0.9 MEM 4.7
===== Item 5485/14800 =====
This is the title of this item
Info: some note
Test finished. Result FooBar. Time 7 secunds.
Stats: CPU 2.5 MEM 2.8"""
p = re.compile("^=====[^=]*=====\n(.*)$\nInfo: .*\n.*Result ([^\.]*)\.",
re.MULTILINE)
for m in re.finditer(p, data):
print "title:", m.group(1), "result:", m.group(2)er code here
import itertools, re
p = re.compile("Result ([^.]*)\.", re.MULTILINE)
for sep, item in itertools.groupby(file('daniels.log'),
lambda x: x.startswith('===== Item ')):
if not sep:
title = item.next().strip()
m = p.search(''.join(item))
if m:
print (title, m.group(1))