2013-11-23 5 views
1

Когда захват группы сопровождается знаком вопроса, то, как представляется, обратная ссылка недоступнаPerl - backreference недоступно, если группа захвата сопровождается?

my $test = "this is a very long day indeed"; 

if ($test =~ m/^this.+(very).+(indeed)?/) { 
    print "It matched the regex.\n"; 
    print "$1 :: $2\n"; 
} 

Печатается

It matched the first test. 
very :: 

Это нормальное поведение? Я не могу найти упоминания об этом в любой документации. Я пытаюсь сопоставить строки в файле журнала, где вторая группа захвата может существовать или не существовать.

+0

Возможный дубликат: http://stackoverflow.com/questions/12683713/optional-capture-group-not-capturing – Enissay

ответ

4

Это не проблема обратной связи. Символы из вашей последней группы сопоставляются .+, но не вашей дополнительной группой захвата, поэтому эта последняя группа соответствует пустой строке.

Проблема в том, что вы используете жадный квантификатор, который соответствует всем возможным символам. Поскольку ваша последняя группа не является обязательной, .+ соответствует всем до конца строки, для механизма regex не требуется возврат к строке (и не нужно «действительно»).

Простой способ решить проблему заключается в использовании ленивого квантора вместо и концевой якоря, чтобы заставить идти до конца линии (потому что ленивый квантор останавливается, как только возможно):

m/^this.+(very).+?(indeed)?$/ 

примечание: если «действительно» не всегда последние символы строки, вы должны добавить .* до $

+0

Не работает: http://regex101.com/r/xF1vF5 – Enissay

+0

@Enissay: это теперь исправляется. –

+0

[Действительно] (http://regex101.com/r/bP7aI1) :) – Enissay

1

Это дополнительное примечание о greedyness, которая была ваша проблема (что получил ответил Казимиром).

Поймите, что по умолчанию все регулярные выражения будут потреблять все, что может, пока не найдет то, что удовлетворяет подвыражению справа от текущего подвыражения оценки.

Каждый раз, когда вы думаете, что использовать жадный квантификатор с метафором DOT, необходимо поднять красный флаг, чтобы подумать дважды. Он ударит прямо из-за того, что вы, возможно, собираетесь махать, если это возможно.

По этой причине попробуйте заменить это чем-то более конкретным, у которого нет возможности пройти мимо намеченной цели.

Модифицировать пример регулярного выражения немного показывает, как это может произойти.

my $test = "this is a very long day indeed, very long."; 

if ($test =~ m/ 

    ^
     (this)    # (1) 
     (.+)     # (2) 
     (very)    # (3) 
     (.+)     # (4) 
     (indeed)?   # (5) 

/x) { 
    print "All = '$&'\n"; 
    print "grp1 = '$1'\n"; 
    print "grp1 = '$2'\n"; 
    print "grp1 = '$3'\n"; 
    print "grp1 = '$4'\n"; 
} 

# Output >> 
# 
# All = 'this is a very long day indeed, very long.' 
# grp1 = 'this' 
# grp1 = ' is a very long day indeed, ' 
# grp1 = 'very' 
# grp1 = ' long.' 
# 
Смежные вопросы