2009-11-06 26 views
7

Ich versuche, eine Protokolldatei zu lesen und einige Maschinen-/Einstellungsinformationen mithilfe von regulären Ausdrücken zu extrahieren. Hier ist ein Beispiel aus dem Protokoll:Regulärer Ausdruck - Wiederholungsgruppen

... 
COMPUTER INFO: 
Computer Name:     TESTCMP02 
Windows User Name:    testUser99 
Time Since Last Reboot:  405 Minutes 
Processor:      (2 processors) Intel(R) Xeon(R) CPU   5160 @ 3.00GHz 
OS Version:     5.1 .number 2600:Service Pack 2 
Memory:      RAM: 48% used, 3069.6 MB total, 1567.3 MB free 
ServerTimeOffSet:    -146 Seconds 
Use Local Time for Log:  True 

INITIAL SETTINGS: 
Command Line:     /SKIPUPDATES 
Remote Online:     True 
INI File:      c:\demoapp\system\DEMOAPP.INI 
DatabaseName:     testdb 
SQL Server:     10.254.58.1 
SQL UserName:     SQLUser 
ODBC Source:     TestODBC 
Dynamic ODBC (not defined): True 
... 

Ich mag jeden ‚Block‘ erfassen von Daten, die Kopfzeile als eine Gruppe verwendet wird, und die Daten als zweite (dh „COMPUTER INFO“, „Computername : ....... ") und wiederhole das für jeden Block. Der Ausdruck, wenn so weit hat, ist

(?s)(\p{Lu}{1,} \p{Lu}{1,}:\r\n)(.*\r\n\r\n) 

Dieser den Block in die Gruppen, wie es sollte herauszieht, das ist toll. Aber ich muss es die Aufnahme wiederholen, die ich nicht zu bekommen scheinen. Ich habe mehrere Gruppierungsausdrücke ausprobiert, darunter:

(?s)(?:(\p{Lu}{1,} \p{Lu}{1,}:\r\n)(.*\r\n\r\n))* 

, die korrekt zu sein scheint, aber ich wieder viele NULL-Ergebnis Gruppen mit leeren Gruppenelementwerte. Ich verwende die .NET RegEx-Klasse, um die Ausdrücke anzuwenden. Kann mir hier jemand helfen?

Antwort

12

Es ist nicht möglich zu haben wiederholte Gruppen. Die Gruppe enthält das letzte Spiel.

Sie müssen dies in zwei Probleme zu brechen. Erstens finden jeden Abschnitt:

new Regex(@"(?>^[A-Z\s]+:\s*$)\s*(?:(?!^\S).)*", RegexOptions.Singleline | RegexOptions.Multiline); 

Und dann, in jedem Spiel, verwenden Sie einen anderen regex jedes Feld/Wert in Gruppen entsprechen:

new Regex(@"^\s+(?<name>[^:]*):\s*(?<value>.*)$", RegexOptions.Multiline); 

Der Code, dies verwenden würde etwas aussehen wie folgt aus:

Regex sectionRegex = new Regex(@"(?>^[A-Z\s]+:\s*$)\s*(?:(?!^\S).)*", RegexOptions.Singleline | RegexOptions.Multiline); 
Regex nameValueRegex = new Regex(@"^\s+(?<name>[^:]*):\s*(?<value>.*)$", RegexOptions.Multiline); 
MatchCollection sections = sectionRegex.Matches(logData); 
foreach (Match section in sections) 
{ 
    MatchCollection nameValues = nameValueRegex.Matches(section.ToString()); 
    foreach (Match nameValue in nameValues) 
    { 
     string name = nameValue.Groups["name"].Value; 
     string value = nameValue.Groups["value"].Value; 
     // OK, do something here. 
    } 
} 
+0

Ich verstehe den Ansatz, aber die ersten Ausdrücke gibt keine übereinstimmenden Gruppen zurück, und ich weiß nicht warum. Irgendwelche Vorschläge? – Jason

+0

Im ersten Fall bekommst du keine Gruppe, du erhältst nur eine Übereinstimmung. Ich füge mehr Code zu dem Beispiel hinzu. –

+0

Ich entschuldige mich. Eine, die ich im Code gemacht habe, funktionierte wie ein Zauber. Ich habe die Beispiele in Expresso selbst getestet. Es müssen die Singleline | Multiline-Optionen sein, die ich genauer untersuchen muss, damit ich verstehen kann, wie sie die Ausdrücke funktionieren lassen. Vielen Dank für Ihre Zeit. – Jason

1
((?<header>[^:]+:)(?<content>[^\r\n]+)?\r\n)+ 

oder, wenn Sie leere Zeilen zwischen den einzelnen Posten:

(((?<header>[^:]+:)(?<content>[^\r\n]+)?\r\n)|\r\n)+ 
+0

Sorry ..., die überhaupt nicht funktionieren. Wahrscheinlich aufgrund der .Net-Parsing-Engine. Ich lasse meine Ausdrücke durch Expresso laufen, um zu simulieren. – Jason

1

Hier ist, wie ich es gehen würde. Dies würde Ihnen erlauben, den Wert einer bestimmten Gruppe leicht zu erhalten, aber der Ausdruck wäre etwas komplizierter. Ich füge Zeilenvorschübe hinzu, um das Lesen zu erleichtern. Hier ist der Anfang:

COMPUTER INFO:.*Computer Name:\s*(?<ComputerName>[\w\s]+).*Windows User Name:\s*(?<WindowUserName>[\w\s]+).*Time Since Last Reboot:\s*(?<TimeSinceLastReboot>[\w\s]+).* (?# This continues on through each of the lines...) 

mit Comiled, IgnoreCase, Einleiner und CultureInvariant

Dann würden Sie in der Lage sein, diese ex über die Gruppen entsprechen:

string computerName = match.Group["ComputerName"].Value; 
string windowUserName = match.Group["WindowUserName"].Value; 
// etc. 
+0

Ich hatte darüber nachgedacht, aber die Gruppen sind nicht endlich. Der Entwickler kann später weitere Blöcke hinzufügen oder einige können fehlen. Ich kann den Anfang der Gruppe von Blöcken identifizieren, muss jedoch eine beliebige Anzahl von ihnen verarbeiten. – Jason