2009-06-10 10 views
2

Ich brauche ein Protokoll in folgendem Format zu analysieren:Wie würde ich das folgende Protokoll analysieren?

===== 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 

Ich muss nur Titel jeder Punkt extrahieren (nächste Zeile nach ===== ===== Artikel 5484/14800) und das Ergebnis .
Also ich muss nur die Zeile mit dem Titel des Artikels und das Ergebnis für diesen Titel behalten und alles andere verwerfen.
Das Problem ist, dass manchmal ein Element Notizen (Max. 3) hat und manchmal das Ergebnis ohne zusätzliche Notizen angezeigt wird, so dass es schwierig ist.
Jede Hilfe wäre willkommen. Ich mache den Parser in Python, aber brauche nicht den eigentlichen Code, aber einige zeigen, wie könnte ich das erreichen?

LE: Das Ergebnis, denn ich bin auf der Suche ist alles andere und sich zu verwerfen, so etwas wie:

('This is the item title','Foo') 
then 
('This is this items title','Bar') 
+1

Es wäre sehr hilfreich, die genaue Ausgabe zu sehen, die Sie sehen möchten. etwas wie [('Artikel 5483/14800', '12') ...]? – Triptych

+2

grep -A1 -E "^ === |^Test" $ LOGFILE | grep -B2 "Test beendet" | grep -v - - | sed -e '$! N; s/\ n//' -e "s/Test abgeschlossen. \ ([^.] * \) \ .. * /, \ 1 /" VERWENDUNG von GNU grep 2.2 Dies ist der Titel des Artikels, Ergebnis Foo Dies ist der Titel dieses Artikels, Ergebnisbalken Dies ist der Titel dieses Artikels, Ergebnis FooB –

+0

Warum nicht grep verwenden? –

Antwort

5
1) Loop through every line in the log 

    a)If line matches appropriate Regex: 

     Display/Store Next Line as the item title. 
     Look for the next line containing "Result 
     XXXX." and parse out that result for 
     including in the result set. 

EDIT: hinzugefügt ein bisschen mehr jetzt, dass ich das Ergebnis sehen Sie suchen .

+0

+1 ... das OP hat es auf diese Weise angefordert "Jede Hilfe wäre willkommen. Ich mache den Parser in Python, brauche aber nicht den eigentlichen Code, aber einige deuten darauf hin, wie ich das erreichen könnte?" – basszero

+0

Gute Sache, er wollte nicht Code, ich weiß nicht, Python einen verdammten Wert :) –

0

Das Parsen wird nicht mit Regex durchgeführt. Wenn Sie einen einigermaßen gut strukturierten Text haben (der so aussieht wie Sie), können Sie einen schnelleren Test verwenden (z. B. line.startswith() oder so). Eine Liste von Wörterbüchern scheint ein geeigneter Datentyp für solche Schlüssel/Wert-Paare zu sein. Ich bin mir nicht sicher, was ich dir sonst noch sagen soll. Das scheint ziemlich trivial zu sein.


OK, so dass die regexp Weg erwies sich als besser geeignet in diesem Fall:

import re 
re.findall("=\n(.*)\n", s) 

ist schneller als Listenkomprehensionen

[item.split('\n', 1)[0] for item in s.split('=\n')] 

Hier ist, was ich habe:

>>> len(s) 
337000000 
>>> test(get1, s) #list comprehensions 
0:00:04.923529 
>>> test(get2, s) #re.findall() 
0:00:02.737103 

Lektion gelernt.

1

Vielleicht so etwas wie (log.log ist Ihre Datei):

def doOutput(s): # process or store data 
    print s 

s='' 
for line in open('log.log').readlines(): 
    if line.startswith('====='): 
     if len(s): 
      doOutput(s) 
      s='' 
    else: 
     s+=line 
if len(s): 
    doOutput(s) 
1

Ich würde empfehlen, eine Schleife beginnen, die in der Zeile für die „===“ aussieht. Lassen Sie das den Titel, der die nächste Zeile ist. Setzen Sie ein Flag, das nach den Ergebnissen sucht. Wenn Sie die Ergebnisse nicht finden, bevor Sie das nächste "===" drücken, sagen Sie keine Ergebnisse. Andernfalls protokollieren Sie die Ergebnisse mit dem Titel. Setzen Sie Ihre Flagge zurück und wiederholen Sie. Sie könnten die Ergebnisse auch mit dem Titel in einem Wörterbuch speichern, speichern Sie einfach "Keine Ergebnisse", wenn Sie die Ergebnisse zwischen dem Titel und der nächsten "===" Zeile nicht finden.

Dies sieht ziemlich einfach auf der Grundlage der Ausgabe zu tun.

0

Man könnte so etwas wie dies versucht (in c-wie Pseudo-Code, da ich Python nicht kennen):

string line=getline(); 
regex boundary="^==== [^=]+ ====$"; 
regex info="^Info: (.*)$"; 
regex test_data="Test ([^.]*)\. Result ([^.]*)\. Time ([^.]*)\.$"; 
regex stats="Stats: (.*)$"; 
while(!eof()) 
{ 
    // sanity check 
    test line against boundary, if they don't match, throw excetion 

    string title=getline(); 

    while(1) 
    { 
    // end the loop if we finished the data 
    if(eof()) break; 

    line=getline(); 
    test line against boundary, if they match, break 
    test line against info, if they match, load the first matched group into "info" 
    test line against test_data, if they match, load the first matched group into "test_result", load the 2nd matched group into "result", load the 3rd matched group into "time" 
    test line against stats, if they match, load the first matched group into "statistics" 
    } 

    // at this point you can use the variables set above to do whatever with a line 
    // for example, you want to use title and, if set, test_result/result/time. 

} 
-1

Hier einige nicht so gut Perl-Code suchen, der die Arbeit erledigt. Vielleicht können Sie es in irgendeiner Weise nützlich finden. Schneller Hack, es gibt andere Möglichkeiten, dies zu tun (ich finde, dass dieser Code verteidigt werden muss).

#!/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"; 
} 
5

Ich weiß, dass Sie nicht für echten Code gefragt haben, aber das ist ein zu große Chance für einen Generator-basierten Text muncher verzichten:

# 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') 

Hoffentlich ist das einfach genug. Fragen Sie, ob Sie Fragen dazu haben, wie genau das oben genannte funktioniert.

1

Regulärer Ausdruck mit Gruppenanpassung scheint die Arbeit in Python zu tun:

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 

Wenn Sie benötigen weitere Informationen über reguläre Ausdrücke überprüfen: python docs.

+0

netter Einsatz von Multiline. Das einzige Problem ist, dass es nicht sehr gut skaliert (Sie müssen die gesamte Datei auf einmal im Speicher halten) – Triptych

+0

Wie wäre es, wenn er itertools.groupby durch die Elemente gehen würde? – oylenshpeegul

+0

Es ist eher ein Vorschlag als eine vollständige Lösung. Es wird besser skalieren, wenn es in einen Puffer liest, bis die Zeile mit "=====" beginnt. Dann kann der Puffer mit dem obigen re analysiert werden. – maciejka

1

Dies ist eine Art Fortsetzung der Maciejka-Lösung (siehe die Kommentare dort). Wenn sich die Daten in der Datei daniels.log befinden, können wir sie mit itertools.groupby Element für Element durchgehen und ein mehrzeiliges Regexp auf jedes Element anwenden. Dies sollte gut skalieren.

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)) 
Verwandte Themen