2009-11-06 12 views
7

Estoy tratando de leer un archivo de registro y extraer información de máquina/configuración mediante expresiones regulares. Este es un ejemplo del registro:Expresión regular - Grupos de repetición

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

Me gustaría capturar cada 'bloque' de los datos, utilizando el encabezado como un solo grupo, y los datos mientras que un segundo (es decir, "INFO ORDENADOR", "Nombre de equipo : ....... ") y repita esto para cada bloque. La expresión si tiene hasta ahora es

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

Esto saca el bloque a los grupos como debería, lo cual es genial. Pero necesito que repita la captura, que parece que no puedo obtener. He intentado varias expresiones de agrupación, entre ellos:

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

lo que parece ser correcta, pero me da la espalda un montón de grupos resultado nulo con valores de los elementos del grupo vacío. Estoy usando la clase .Net RegEx para aplicar las expresiones, ¿alguien puede ayudarme aquí?

Respuesta

12

No es posible tener grupos repetidos. El grupo contendrá el último partido.

Tendrá que dividir esto en dos problemas. En primer lugar, encontrar cada sección:

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

Y luego, dentro de cada partido, utilizar otra expresión regular para que coincida con cada campo/valor en grupos:

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

El código para utilizar este sería algo de esta manera:

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

Entiendo el enfoque, pero las primeras expresiones no devuelven grupos coincidentes, y no sé por qué. ¿Alguna sugerencia? – Jason

+0

En el primer caso, no estás obteniendo un grupo, solo estás obteniendo una coincidencia. Agregaré más código al ejemplo. –

+0

Lo disculpo. Uno lo hice en código, funcionó como un encanto. Estaba probando los ejemplos por sí mismos en Expresso. Deben ser las opciones de línea única (Singleline), que tendré que explorar con más detalle para poder entender cómo hacen que las expresiones funcionen. Muchas gracias por tu tiempo. – Jason

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

o, si tiene líneas en blanco entre los objetos:

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

Lo siento ... que no funcionó en absoluto. Probablemente debido al motor de análisis .Net. Estoy ejecutando mis expresiones a través de Expresso para simular. – Jason

1

Aquí es cómo iba a ir sobre ella. Esto le permitiría obtener el valor de un grupo específico fácilmente, pero la expresión sería un poco más complicada. Agrego líneas de alimentación para que sea más fácil de leer. Aquí está el comienzo:

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 y CultureInvariant

allí tendría que ser capaz de igualar esto a través de los Grupos de ex:

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

Había pensado en hacer eso, pero los grupos no son finitos. El desarrollador puede agregar más bloques más tarde, o algunos pueden faltar. Puedo identificar el comienzo del grupo de bloques, pero necesito procesar cualquier número de ellos. – Jason

Cuestiones relacionadas