2009-12-26 5 views
0

Pourquoi cette expression ne suit pas l'approche gourmande?Pourquoi cette expression ne suit pas l'approche gourmande?

string input = @"cool man! your dog can walk on water "; 
string pattern = @"cool (?<cool>(.*)) (?<h>((dog)*)) (?(h)(?<dog>(.*))) "; 

MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); 


foreach (Match match in matches) 
{ 
    Console.WriteLine("cool=" + match.Groups["cool"].Value); 
    Console.WriteLine("dog=" + match.Groups["dog"].Value); 
    Console.ReadLine(); 
} 

Sortie:

 
cool= man! your dog can walk on water 
dog= 

Comme vous pouvez le constater: groupe (chien) est adapté 0 times.But puisque, * est gourmand, pourquoi ne pas tente de trouver des correspondances maximales de (chien) qui est 1?

Des indices?

+0

? restreint la gourmandise –

Répondre

7

Le premier .* correspond initialement à la chaîne entière. Ensuite, le moteur regex détermine s'il doit reculer pour correspondre au reste de l'expression régulière. Mais (?<h>((dog)*)) et (?(h)(?<dog>(.*))) peuvent légalement correspondre à zéro caractères, donc aucun retour en arrière n'est nécessaire (en ce qui concerne le .*). Essayez d'utiliser un .*? non-avide dans cette partie.

EDIT (en réponse à l'information supplémentaire publiée dans la réponse ci-dessous): D'accord, le remplacement du premier .* avec un .*?non gourmand ne ont un effet, mais pas celui que vous voulez. Où tout après le mot "cool" a été capturé dans le groupe <cool> avant, maintenant il est capturé dans le groupe <dog>. Voici ce qui se passe:

Après que le mot "cool" a été trouvé, (?<cool>(.*?)) ne correspond initialement à rien (le contraire du comportement glouton), et (?<h>((dog)*)) essaie de faire correspondre. Cette partie réussira toujours, peu importe où elle est essayée, car elle peut correspondre à "chien" ou à une chaîne vide. Cela signifie que l'expression conditionnelle dans (?(h)...) sera toujours évaluée à true, donc il va de l'avant et correspond au reste de l'entrée avec (?<dog>(.*)). Si je comprends bien, vous voulez faire correspondre tout après "cool" dans le groupe nommé <cool>, sauf si la chaîne contient le mot "dog"; alors vous voulez capturer tout après "chien" dans le groupe nommé <dog>. Vous essayez d'utiliser un conditional pour cela, mais ce n'est pas vraiment le bon outil. Il suffit de faire ceci:

string pattern = @"cool (?<cool>.*?) (dog (?<dog>.*))?$"; 

La clé ici est la $ à la fin; il force le non-gourmand .*? à continuer à correspondre jusqu'à ce qu'il atteigne la fin de la chaîne. Parce qu'il n'est pas gourmand, il essaie de faire correspondre la partie suivante de l'expression régulière, (dog (?<dog>.*)), avant de consommer chaque caractère. Si le mot "chien" est présent, le reste de la chaîne sera consommé par (?<dog>.*); Si ce n'est pas le cas, l'expression régulière réussit toujours car le ? rend cette partie entière facultative.

0

Je n'essayé non avide (.*?) mais il n'a pas d'effet qui est évident que (.*?) non avides représente {0,1} depuis .and même zéro caractères ici correspond, donc pas d'effet.

Des idées comment le corriger.Je veux dire, je veux capturer la chaîne suivie par (dog) si son présent là ou bien le groupe précédent capturera la chaîne (cool(.*))

Le problème est que (dog) est facultative et si son présent, nous avons besoin de la chaîne qui le suit.

L'utilisation de (dog)? n'a aucun effet car elle correspond à nouveau à zéro caractère.

Merci.

+0

Je pense que vous avez une mauvaise idée des quantificateurs non gourmands; lisez ceci: http://www.regular-expressions.info/repeat.html Pour le reste, voir ma modification à ma réponse originale. –

Questions connexes