Максимальное количество захваченных групп в регулярном выражении Perl

Учитывая регулярное выражение в Perl, как мне найти максимальное количество захваченных групп в этом регулярном выражении? Я знаю, что могу использовать $1, $2 и т. Д. Для ссылки на первую, вторую и т. Д. Захваченные группы. Но как мне найти максимальное количество таких групп? Под захваченными группами я подразумеваю строку, совпадающую с регулярным выражением в парантезе. Например: если регулярное выражение равно (a+)(b+)c+, то строка "abc" соответствует этому регулярному выражению. И первая захваченная группа будет 1 доллар, вторая будет 2 доллара.

3 ответа

Решение

amon намекнул на ответ на этот вопрос, когда он упомянул %+ хэш. Но то, что вам нужно, это @+ массив:

@+

Этот массив содержит смещения концов последних успешных субматч в текущей активной динамической области. $+[0] - это смещение в строке конца всего совпадения. Это то же значение, которое возвращает функция pos при вызове переменной, с которой сопоставлено. N-й элемент этого массива содержит смещение n-го субматча, поэтому $ + 1 - это смещение за прошлым, где заканчивается $1, $+[2] смещение за прошлым, где заканчивается $2, и так далее. Вы можете использовать $#+, чтобы определить, сколько подгрупп было в последнем успешном совпадении. Смотрите примеры, приведенные для переменной @-. [ добавлен энфазис ]

$re = "(.)" x 500;
$str = "a" x 500;
$str =~ /$re/;
print "Num captures is $#+";      #  outputs "Num captures is 500"

Количество снимков практически не ограничено. Хотя может быть только девять снимков, к которым вы можете получить доступ с помощью $1-$9 переменные, вы можете использовать больше групп захвата.

Если у вас есть несколько групп захвата, вы можете использовать именованные захваты, такие как

my $str = "foobar";

if ($str =~ /(?<name>fo+)/) {
  say $+{name};
}

Выход: foo, Вы можете получить доступ к значениям именованных захватов через %+ хэш.

Вы можете использовать код, подобный следующему, чтобы подсчитать количество групп захвата:

$regex = qr/..../; # Some arbitrary regex with capture groups
my @capture = '' =~ /$regex|()/;   # A successful match incorporating the regex 
my $groups_in_my_regex = scalar(@capture) - 1;

Он работает так, что выполняет сопоставление, которое должно быть успешно выполнено, а затем проверяет, сколько групп захвата было создано. (Из-за трейлинга создается дополнительный |()

Изменить: На самом деле, нет необходимости добавлять дополнительную группу захвата. До тех пор, пока совпадение гарантированно будет успешным, массив будет содержать запись для каждой группы захвата.

Таким образом, мы можем изменить 2-ю и 3-ю строки на:

my @capture = '' =~ /$regex|/;   # A successful match incorporating the regex 
my $groups_in_my_regex = scalar(@capture);

Смотрите также:
Считать группы захвата в регулярном выражении qr?

Другие вопросы по тегам