Почему Perl ленив, когда регулярное выражение совпадает с * в группе?

В perl * обычно жадный, если вы не добавите ? после него. Однако, когда * используется против группы, ситуация кажется иной. Мой вопрос "почему". Рассмотрим этот пример:

my $text = 'f fjfj ff';
my (@matches) = $text =~ m/((?:fj)*)/;
print "@matches\n";
# --> ""
@matches = $text =~ m/((?:fj)+)/;
print "@matches\n";
# --> "fjfj"

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

@matches = $text =~ m/((?:..)*)/;
print "@matches\n";
# --> 'f fjfj f'
  • Примечание. Вышеописанное было проверено на perl 5.12.
  • Примечание. Неважно, использую ли я захватывающие или не захватывающие круглые скобки для внутренней группы.

Ответ 1

Это не вопрос жадного или ленивого повторения. (?:fj)* жадно сопоставляет столько повторений "fj", сколько может, но он будет успешно соответствовать нулевым повторениям. Когда вы попытаетесь сопоставить его со строкой "f fjfj ff", она сначала попытается совпадения в позиции нуля (до первого "f" ). Максимальное количество раз, когда вы можете успешно сопоставить "fj" в нуле нулевой позиции, равно нулю, поэтому шаблон успешно соответствует пустой строке. Поскольку шаблон успешно сопоставлен с нулевым положением, мы закончили, и у двигателя нет причин попробовать совпадение в более поздней позиции.

Мораль этой истории: не пишите шаблон, который не может ничего сопоставить, если вы не хотите, чтобы он ничего не соответствовал.

Ответ 2

Perl будет соответствовать как можно раньше в строке (самый левый). Он может сделать это с вашим первым совпадением, сопоставляя нулевые вхождения fj в начале строки