2008-09-03 19 views
2

Ich arbeite gerade an einem Parser für unsere internen Protokolldateien (generiert von log4php, log4net und log4j). Bis jetzt habe ich einen schönen regulären Ausdruck, um die Logs zu analysieren, bis auf ein nerviges Bit: Einige Log-Nachrichten erstrecken sich über mehrere Zeilen, die ich nicht richtig zuordnen kann. Die Regex ich jetzt habe, ist dies:Eine Protokolldatei mit regulären Ausdrücken analysieren

(?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}):\d{2}:\d{2}),\d{3})\s(?<message>.+) 

Die Log-Format (die ich zum Testen der Parser verwenden), ist dies:

07/23/08 14:17:31,321 log 
message 
spanning 
multiple 
lines 
07/23/08 14:17:31,321 log message on one line 

Wenn ich den Parser jetzt laufen, bekomme ich nur die Zeile Das Protokoll beginnt. Wenn ich es so ändere, dass es sich über mehrere Zeilen erstreckt, erhalte ich nur ein Ergebnis (die gesamte Protokolldatei).


@samjudson: ""

Sie müssen in dem regulären Ausdruck, der die RegexOptions.Singleline Flagge passieren, so dass passt auf alle Zeichen, nicht nur auf alle Zeichen außer neue Zeilen (das ist die Standardeinstellung).

Ich habe das versucht, aber dann stimmt es mit der ganzen Datei überein. Ich habe auch versucht, die Nachrichtengruppe auf. +? (nicht gierig), aber dann stimmt es mit einem einzelnen Zeichen überein (was ich auch nicht suche).

Das Problem ist, dass das Muster für die Nachricht auch auf der Datumsgruppe übereinstimmt, also, wenn es nicht auf einer neuen Zeile bricht, geht es einfach weiter und weiter und weiter.


Ich benutze diese Regex für die Nachrichtengruppe jetzt. Es funktioniert, es sei denn, es gibt ein Muster in der Protokollnachricht, das mit dem Beginn der Protokollnachricht übereinstimmt.

(?<message>(.(?!\d{2}/\d{2}/\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\s\[\d{4}\]))+) 

Antwort

3

Dies funktioniert nur, wenn die Log-Nachricht kein Datum am Anfang der Zeile enthalten, aber Sie könnten versuchen, eine negative Vorgriff Behauptung für ein Datum in der „Botschaft“ Gruppe hinzufügen:

(?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}:\d{2}:\d{2},\d{3})\s(?<message>(.(?!^\d{2}/\d{2}/ 
\d{2}))+) 

Beachten Sie, dass hierfür das Flag RegexOptions.MultiLine erforderlich ist.

0

Sie müssen die RegexOptions übergeben. Singulares Flag im regulären Ausdruck, so dass "." passt auf alle Zeichen, nicht nur auf alle Zeichen außer neue Zeilen (das ist die Standardeinstellung).

1

Das Problem, das Sie haben, ist, dass Sie das RegEx-Muster beenden müssen, damit es weiß, wann eine Nachricht endet und dann als nächstes startet.

Wenn Sie im Standardmodus ausgeführt wurden, funktionierte der Zeilenvorschub als impliziter Abschluss.

Das Problem ist, wenn Sie in den mehrzeiligen Modus gehen, gibt es keinen Terminator, so dass das Muster die ganze Datei verschlingen wird. Nicht gierig passt ein paar Charaktere wie möglich zusammen, die nur eins sind.

Nun, wenn Sie das Datum für die nächste Nachricht als Terminator verwenden, denke ich, dass Ihr Parser nur jede andere Zeile bekommen wird.

Gibt es noch etwas in der Datei, um das Muster zu beenden?

2

Sie müssen offensichtlich, dass "Nachrichten Zeilen" von "Protokollzeilen" unterschieden werden können; Wenn Sie zulassen, dass der Nachrichtenteil mit Datum/Uhrzeit nach einer neuen Zeile beginnt, gibt es einfach keine Möglichkeit zu bestimmen, was Teil einer Nachricht ist und was nicht. Anstatt den Punkt zu verwenden, benötigen Sie einen Ausdruck, der alles erlaubt, was keine Zeilenschaltung gefolgt von Datum und Uhrzeit enthält.

Persönlich würde ich jedoch keinen regulären Ausdruck verwenden, um den gesamten Protokolleintrag zu analysieren.Ich bevorzuge es, meine eigene Schleife zu verwenden, um über jede Zeile zu iterieren und einen einfachen regulären Ausdruck zu verwenden, um zu bestimmen, ob eine Zeile der Anfang eines neuen Eintrags ist oder nicht. Auch von der Lesbarkeit her hätte das meine Präferenz.

0

Sie könnten es viel einfacher finden, die Datei mit einem geeigneten Parsergenerator zu analysieren - ANTLR kann einen in C# erzeugen ... Kontext Kostenlose Parser scheinen nur schwer zu sein, bis Sie sie "bekommen" - danach sind sie viel einfacher und freundlicher zu verwenden als Reguläre Ausdrücke ...

Verwandte Themen