2009-12-26 3 views
0

Почему это выражение не следует жадному подходу?Почему это выражение не следует жадному подходу?

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(); 
} 

Выход:

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

Как вы можете заметить: (собака) группа соответствует 0 times.But так, * жаден, почему он не пытается найти максимальное количество матчей (собака), которая равна 1?

Любые подсказки?

+0

? ограничивает жадность –

ответ

7

Первый .* первоначально соответствует всей строке. Затем механизм регулярных выражений определяет, нужно ли ему отступать, чтобы соответствовать остальному регулярному выражению. Но и (?(h)(?<dog>(.*))) могут легально совпадать с нулевыми символами, поэтому не требуется обратное отслеживание (насколько это касается .*). Попробуйте использовать не-жадный .*? в этой части.

EDIT (в ответ на дополнительную информацию, публикуемую в ответ ниже): Хорошо, заменив первый .* с не жадным .*?делает иметь эффект, только не тот, который вы хотите. Где все после слова «круто» захватывалось в группе <cool> раньше, теперь оно фиксируется в группе <dog>. Вот что происходит:

После того, как слово «cool» соответствует, (?<cool>(.*?)) изначально ничего не соответствует (противоположность жадному поведению) и (?<h>((dog)*)) пытается соответствовать. Эта часть всегда будет успешной независимо от того, где она была опробована, потому что она может соответствовать «собаке» или пустой строке. Это означает, что условное выражение в (?(h)...) всегда будет оцениваться до true, поэтому оно идет вперед и соответствует остальной части ввода с (?<dog>(.*)).

Как я понимаю, вы хотите совместить все после «круто» в названной группе <cool>, если строка не содержит слово «собака»; то вы хотите захватить все после «собаки» в названной группе <dog>. Вы пытаетесь использовать для этого conditional, но это не совсем правильный инструмент. Просто сделайте это:

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

Ключевым моментом здесь является $ в конце; он заставляет не-жадные .*? поддерживать совпадение, пока не достигнет конца строки. Поскольку он не жадный, он пытается сопоставить следующую часть регулярного выражения, (dog (?<dog>.*)), прежде чем потреблять каждый символ. Если слово «собака» есть, остальная часть строки будет потребляться (?<dog>.*); если нет, регулярное выражение все равно будет выполнено, потому что ? делает эту часть необязательной.

0

Я пробовал не жадный (.*?), но он не имеет никакого эффекта, что очевидно как не жадный (.*?) означает {0,1}. Так как даже нулевые символы здесь соответствуют, поэтому никакого эффекта.

Любые идеи, как это исправить.Я имею в виду, я хочу, чтобы захватить строку с последующим (dog), если его там присутствовать, либо предыдущая группа захватит строку (cool(.*))

Проблема заключается в том, что (dog) является необязательным, и если его нет, нам нужна строка после него.

с использованием (dog)? не имеет никакого эффекта, так как он снова соответствует нулевым символам.

Спасибо.

+0

Я думаю, что у вас неправильное представление о не-жадных квантификаторах; прочитайте это: http://www.regular-expressions.info/repeat.html. В остальном, см. мое редактирование к моему первоначальному ответу. –