Почему это выражение не следует жадному подходу? - PullRequest
0 голосов
/ 26 декабря 2009

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

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 раз. Но, поскольку * жаден, почему он не пытается найти максимальное совпадение (собака), которое равно 1?

Есть какие-нибудь подсказки?

Ответы [ 2 ]

7 голосов
/ 26 декабря 2009

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

РЕДАКТИРОВАТЬ (в ответ на дополнительную информацию, размещенную в ответе ниже): Хорошо, замена первого .* ненадежным .*? оказывает влияние, только не тот, который вы хотите. Если раньше все, что было после слова «круто», захватывалось в группе <cool>, то теперь оно захватывается в группе <dog> Вот что происходит:

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

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

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

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

0 голосов
/ 27 декабря 2009

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

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

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

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

Спасибо.

...