Регулярное выражение нежадное — это жадное

У меня есть следующий текст

tooooooooooooon

Согласно этой книге, которую я читаю, когда ? следует за любым квантификатором, он становится нежадным.

Мое регулярное выражение to*?n все еще возвращает tooooooooooooon.

Он должен вернуть ton, не так ли?

Есть идеи, почему?


person Razor    schedule 29.10.2008    source источник


Ответы (5)


Регулярное выражение может соответствовать только существующему фрагменту текста.

Поскольку подстрока 'ton' не существует нигде в вашей строке, она не может быть результатом совпадения. Совпадение вернет только подстроку исходной строки.

РЕДАКТИРОВАТЬ: Чтобы было ясно, если вы использовали строку ниже, с дополнительным 'n'

toooooooonoooooon

это регулярное выражение (которое не указывает "о")

t.*n

будет соответствовать следующему (как можно больше символов перед «n»)

toooooooonoooooon

но регулярное выражение

t.*?n

будет соответствовать только следующему (как можно меньше символов перед «n»)

toooooooon
person Gareth    schedule 29.10.2008
comment
вы также можете использовать регулярное выражение для замены, но оно заменит только совпадения. - person Ady; 29.10.2008
comment
Очень понятное объяснение! Я думаю, что ваш последний пример должен быть изменен с t.*?n на *?n - как есть, t.*?n соответствует всей строке. Подробности смотрите в моем ответе. - person Adam Liss; 02.11.2008
comment
Адам: нет, попробуйте сами на своем любимом языке — я использовал rubular.com/regexes/4760 -- у вас должно быть так же. Все *? находит кратчайшее возможное совпадение, а не самое длинное. - person Gareth; 03.11.2008

Регулярное выражение всегда стремится соответствовать.

Ваше выражение говорит об этом:

A 't', followed by *as few as possible* 'o's, followed by a 'n'.

Это означает, что любой необходимый o будет совпадать, потому что в конце есть 'n', которого выражение стремится достичь. Сопоставление всех букв «о» — это единственная возможность добиться успеха.

person Tomalak    schedule 29.10.2008

Регулярные выражения пытаются сопоставить все в них. Поскольку 'o' не меньше, чем каждый o в toooon, чтобы сопоставить n, все сопоставляется. Кроме того, потому что вы используете o*? вместо о+? вам не требуется присутствие о.

Пример в Перле

$a = "toooooo";
$b = "toooooon";

if ($a =~ m/(to*?)/) {
        print $1,"\n";
}
if ($b =~ m/(to*?n)/) {
        print $1,"\n";
}

~>perl ex.pl
t
toooooon
person Vinko Vrsalovic    schedule 29.10.2008
comment
Я бы использовал ту же строку для проверки. Делает более ясным то, что вы пытаетесь выделить. - person Brad Gilbert; 30.10.2008

Regex всегда делает все возможное, чтобы соответствовать. Единственное, что вы делаете в этом случае, — это замедляете работу парсера, заставляя его возвращаться к узлу /o*?/. Один раз для каждого 'o' в "tooooon". В то время как при обычном сопоставлении потребуется столько 'o's, сколько возможно, в первый раз. Так как следующим элементом для сопоставления является 'n', которому не будет сопоставлен 'o', нет особого смысла пытаться использовать минимальное сопоставление. На самом деле, когда нормальное сопоставление терпит неудачу, для этого потребуется довольно много времени. Он должен возвращаться через каждые 'o', пока не останется ни одного возврата. В этом случае я бы использовал максимальное соответствие /to*+n/. 'o' возьмет все, что сможет, и никогда ничего не вернет. Это сделало бы так, что когда он выходит из строя, он быстро выходит из строя.

Минимальное RE после:

'toooooon' ~~ /to*?n/

 t  o  o  o  o  o  o  n       
{t}                           match [t]
[t]                           match [o] 0 times
[t]<n>                        fail to match [n] -> retry [o]
[t]{o}                        match [o] 1 times
[t][o]<n>                     fail to match [n] -> retry [o]
[t][o]{o}                     match [o] 2 times
[t][o][o]<n>                  fail to match [n] -> retry [o]

. . . .

[t][o][o][o][o]{o}            match [o] 5 times
[t][o][o][o][o][o]<n>         fail to match [n] -> retry [o]
[t][o][o][o][o][o]{o}         match [o] 6 times
[t][o][o][o][o][o][o]{n}      match [n]

Обычное RE успешно:

(ПРИМЕЧАНИЕ: то же самое для максимальной RE)

'toooooon' ~~ /to*n/

 t  o  o  o  o  o  o  n       
{t}                           match [t]
[t]{o}{o}{o}{o}{o}{o}         match [o] 6 times
[t][o][o][o][o][o][o]{n}      match [n]

Отказ минимального RE:

'toooooo' ~~ /to*?n/

 t  o  o  o  o  o  o

. . . .

. . . .

[t][o][o][o][o]{o}            match [o] 5 times
[t][o][o][o][o][o]<n>         fail to match [n] -> retry [o]
[t][o][o][o][o][o]{o}         match [o] 6 times
[t][o][o][o][o][o][o]<n>      fail to match [n] -> retry [o]
[t][o][o][o][o][o][o]<o>      fail to match [o] 7 times -> match failed

Отказ нормального RE:

'toooooo' ~~ /to*n/

 t  o  o  o  o  o  o       
{t}                           match [t]
[t]{o}{o}{o}{o}{o}{o}         match [o] 6 times
[t][o][o][o][o][o][o]<n>      fail to match [n] -> retry [o]
[t][o][o][o][o][o]            match [o] 5 times
[t][o][o][o][o][o]<n>         fail to match [n] -> retry [o]

. . . .

[t][o]                        match [o] 1 times
[t][o]<o>                     fail to match [n] -> retry [o]
[t]                           match [o] 0 times
[t]<n>                        fail to match [n] -> match failed

Отказ максимального RE:

'toooooo' ~~ /to*+n/

 t  o  o  o  o  o  o
{t}                           match [t]
[t]{o}{o}{o}{o}{o}{o}         match [o] 6 times
[t][o][o][o][o][o][o]<n>      fail to match [n] -> match failed
person Brad Gilbert    schedule 30.10.2008

Строка, в которой вы ищете (так сказать, стог сена), не содержит подстроки «ton».

Однако он содержит подстроку «tooooooooooooon».

person Hank    schedule 29.10.2008
comment
Кроме того, ваше регулярное выражение может возвращать только то, что оно может найти. Он не может найти «тонну» в вашей строке, потому что он не существует, но МОЖЕТ найти «тоооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо... - person Matthew Scharley; 29.10.2008
comment
Отличный комментарий, я добавлю это для ясности. - person Hank; 29.10.2008