2009-05-13 8 views
0

J'ai des données texte dans ce format:Expression régulière question de regroupement

MI 
00 
3 

MD 
1 
0.0000 
MD 
2 
0.0000 
MD 
3 
0.0000 

Ce bloc peut être répété et le nombre de MDs est variable (mais toujours> = 1) et les valeurs numériques suivantes doivent être capturé pour chacun.

J'ai une regex qui correspond à tous les MD par MI, mais elle ne capture que le dernier MD. Est-il possible de capturer chaque MD sans savoir à l'avance combien il y en a?

EDIT: Par demande ... Regex est ci-dessous; la partie importante de ma question demeure: "Puis-je capturer tous les MD?"

MI\r\d\d\r(\d)\r[\s\w]{6}\r(MD\r[\s\d]{2}\r[\s\d\.\-]*\r)+ 

Ma langue de choix est C#, mais je prendrais une réponse dans toutes les langues, car elle au moins me donner un début.

MD est un point de données d'un détecteur de soufre du début des années 90.

+0

Ajoutez votre regex, la langue du client, et peut-être expliquer ce qu'est MD? – Andomar

Répondre

3

Chaque match a une collection Groupes. Dans votre cas, les correspondances [0] .Groupes [1] correspondent aux enregistrements MD, comme "MD \ n1 \ n00.00MD \ n2 \ n0.0000MD \ n3 \ n0.0000".

Chaque groupe a un Captures collection, que vous pouvez parcourir pour trouver toutes les instances de MD. Cela vous donnera une chaîne par MD, donc Matches [0] .Groups [1] .Captures [0] sera "MD \ n1 \ n0.0000".

EDIT: Bien que vous avez déjà accepté la réponse, voici une façon d'analyser tout en une seule fois:

string pat = @"MI[\r\n]*(?<MI1>\d\d)[\r\n]*(?<MI2>\d+)[\r\n]*" + 
    @"(MD[\r\n]*(?<MD1>\d+)*[\r\n]*(?<MD2>[\d\.\-]+)+[\r\n]*)*"; 

var r = new Regex(pat); 
foreach (Match match in r.Matches(text)) 
{ 
    Console.WriteLine("MI v1:{0} v2:{1}", 
     match.Groups["MI1"], match.Groups["MI2"]); 

    if (match.Groups.Count > 2) 
     for (var i = 0; i < match.Groups["MD1"].Captures.Count; i++) 
      Console.WriteLine(" MD v1:{0} v2:{1}", 
       match.Groups["MD1"].Captures[i], 
       match.Groups["MD2"].Captures[i]); 
} 

Ceci est le texte de test je:

MI 
00 
3 

MD 
1 
0.1000 
MD 
2 
0.2000 
MD 
3 
0.3000 

MI 
12 
5 

MI 
24 
5 

MD 
1 
0.1000 

La sortie est:

MI v1:00 v2:3 
    MD v1:1 v2:0.1000 
    MD v1:2 v2:0.2000 
    MD v1:3 v2:0.3000 
MI v1:12 v2:5 
MI v1:24 v2:5 
    MD v1:1 v2:0.1000 
+0

Exactement ce que je cherchais. Merci! –

2

Il est possible, mais il faudra plus d'un passage sur les données. Un groupe regex ne peut contenir qu'un seul bloc d'informations par match. Ainsi, vous pourriez avoir un groupe MD et trouver toutes vos correspondances MD ou un groupe MI qui contenait un groupe MD et qui trouverait toutes vos correspondances MI ... mais le groupe MD ne serait pas séparé.

Une solution est des appels regex imbriqués, le premier trouvant chaque groupe MI et le second trouvant chaque groupe MD dans le groupe MI.

0

Je pense que cela va le faire. Au moins cela fonctionne avec RegexBuddy en utilisant Perl.

MD[^MI]* 

Les données sont simplement répétées ci-dessus.

EDIT: Cela semble capturer tous les MD et le MI initial dans son propre petit bloc.

MI([^MI]*(MD[^MI]*)*) 
+0

Comment gérez-vous le regroupement? –

+0

Je suppose que je ne comprends pas ce que vous entendez par regroupement. Avez-vous besoin d'attacher chaque MD avec l'IM spécifique? – Keng

0

Je ne suis pas un expert en C#, mais en Java, vous voulez changer (MD ...) + à ((MD ...) +). De cette façon, vous pouvez utiliser la paire de parenthèses extérieure pour capturer tous les MD.

0

Je vous recommande de mettre en œuvre un state machine pour cette tâche ..

Mais voici une expression rationnelle, je pense également travailler:

MI\r\d\d\r(\d)\r\r(MD\r\d\r[0-9\.]+\r?)*