2009-11-06 17 views
7

Sto cercando di leggere un file di registro ed estrarre alcune informazioni sulla macchina/sull'impostazione utilizzando le espressioni regolari. Ecco un esempio dal registro:Espressione regolare - Gruppi ripetuti

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

Vorrei catturare ogni 'blocco' dei dati, utilizzando l'intestazione come un unico gruppo, e i dati come un secondo (vale a dire "INFO COMPUTER", "Nome computer : ....... ") e ripetere questo per ogni blocco. L'espressione se è stata finora è

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

Questo estrae il blocco nei gruppi come dovrebbe, il che è ottimo. Ma ho bisogno di farlo ripetere la cattura, che non riesco a ottenere. Ho provato diverse espressioni di raggruppamento, tra cui:

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

che sembrerebbe essere corretto, ma torno un sacco di gruppi risultato nullo con valori delle voci di gruppo vuoto. Sto usando la classe .Net RegEx per applicare le espressioni, qualcuno può aiutarmi qui?

risposta

12

Non è possibile avere gruppi ripetuti. Il gruppo conterrà l'ultima partita.

È necessario suddividere questo in due problemi. In primo luogo, trovare ogni sezione:

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

E poi, all'interno di ogni partita, utilizzare un altro regex per abbinare ogni campo/valore in gruppi:

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

Il codice per utilizzare questo apparirebbe qualcosa in questo modo:

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

Capisco l'approccio, ma le prime espressioni non restituiscono i gruppi corrispondenti, e non so perché. Eventuali suggerimenti? – Jason

+0

Nel primo caso, non si ottiene un gruppo, si sta solo ottenendo una corrispondenza. Aggiungerò altro codice all'esempio. –

+0

Mi chiedo. Uno ho fatto questo in codice, ha funzionato come un fascino. Stavo provando gli esempi da soli in Expresso. Devono essere le opzioni Singleline | Multiline, che dovrò esplorare con maggiori dettagli in modo da capire come fanno funzionare le espressioni. La ringrazio molto per il vostro tempo. – Jason

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

o, se si dispone di linee vuote tra gli elementi:

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

dispiace ... che non ha funzionato affatto. Probabilmente a causa del motore di analisi .Net. Sto facendo funzionare le mie espressioni attraverso Expresso per simulare. – Jason

1

Ecco come vorrei andare a questo proposito. Ciò consentirebbe di ottenere facilmente il valore di un gruppo specifico ma l'espressione sarebbe un po 'più complicata. Aggiungo i line feed per renderlo più facile da leggere. Ecco l'inizio:

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...) 

con Comiled, IgnoreCase, SingleLine, e CultureInvariant

Poi si sarebbe in grado di corrispondere a questo attraverso il gruppi es:

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

Avevo pensato di farlo, ma i gruppi non sono finiti. Lo sviluppatore potrebbe aggiungere più blocchi in un secondo momento o alcuni potrebbero non essere disponibili. Posso identificare l'inizio del gruppo di blocchi, ma è necessario elaborare un numero qualsiasi di essi. – Jason