2009-11-06 9 views
7

J'essaie de lire un fichier journal et d'extraire des informations sur les machines/paramètres en utilisant des expressions régulières. Voici un exemple du journal:Expression régulière - Répétition de groupes

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

Je voudrais saisir chaque « bloc » des données, en utilisant l'en-tête en tant que groupe, et les données en tant que seconde (ie « INFO INFORMATIQUE », « Nom de l'ordinateur : ....... ") et répétez ceci pour chaque bloc. L'expression "si" a été jusqu'à présent

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

Ceci retire le bloc dans les groupes comme il se doit, ce qui est génial. Mais j'ai besoin de répéter la capture, ce que je n'arrive pas à obtenir. J'ai essayé plusieurs expressions de regroupement, y compris:

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

qui semble être correct, mais je reviens beaucoup de groupes de résultats NULL avec les valeurs des éléments du groupe vide. J'utilise la classe .Net RegEx pour appliquer les expressions, quelqu'un peut-il m'aider ici?

Répondre

12

Il est impossible d'avoir groupes répétés. Le groupe contiendra le dernier match.

Vous aurez besoin de décomposer ceci en deux problèmes. Tout d'abord, trouver chaque section:

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

Et puis, dans chaque match, utilisez un autre regex pour correspondre à chaque champ/valeur en groupes:

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

Le code à utiliser ressemblerait à quelque chose comme ceci:

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

Je comprends l'approche, mais les premières expressions ne retournent pas les groupes correspondants, et je ne sais pas pourquoi. Aucune suggestion? – Jason

+0

Dans le premier cas, vous n'obtenez pas de groupe, vous obtenez juste une correspondance. Je vais ajouter plus de code à l'exemple. –

+0

Je m'excuse. Un que j'ai fait ceci dans le code, cela a fonctionné comme un charme. J'essayais les exemples par eux-mêmes dans Expresso. Ce doit être les options Singleline | Multiline, que je devrai explorer plus en détail pour que je puisse comprendre comment elles fonctionnent. Merci beaucoup pour votre temps. – Jason

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

ou, si vous avez des lignes vides entre les éléments:

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

Désolé ... qui ne fonctionne pas du tout. Probablement en raison du moteur d'analyse .Net. Je cours mes expressions à travers Expresso pour simuler. – Jason

1

Voici comment j'aller à ce sujet. Cela vous permettrait d'obtenir facilement la valeur d'un groupe spécifique, mais l'expression serait un peu plus compliquée. J'ajoute des sauts de ligne pour le rendre plus facile à lire. Voici le début:

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

avec Comiled, IgnoreCase, SingleLine et CultureInvariant

Ensuite, vous seriez en mesure de faire correspondre ce via les groupes ex:

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

J'avais pensé à faire ça, mais les groupes ne sont pas finis. Le développeur peut ajouter plus de blocs plus tard, ou certains peuvent être manquants. Je peux identifier le début du groupe de blocs, mais j'ai besoin de traiter n'importe quel nombre d'entre eux. – Jason

Questions connexes