Ответ 1
Вы можете использовать что-то вроде:
sub capturing_groups{
my $re = shift;
"" =~ /|$re/;
return $#+;
}
say capturing_groups qr/fo(.)b(..)/;
Вывод:
2
Я работаю над проектом, который в какой-то момент получает список файлов с ftp-сервера. В этот момент он либо возвращает arrayref файлов, либо если передана необязательная ссылка regex (т.е. qr
), она фильтрует список вниз с помощью grep. Кроме того, если qr
имеет группу захвата, он обрабатывает захваченный раздел как номер версии и возвращает вместо него hashref, где ключи являются версиями, а значениями являются имена файлов (которые были бы возвращены как массив, если нет захвата группы). Код выглядит (слегка упрощен)
sub filter_files {
my ($files, $pattern) = @_;
my @files = @$files;
unless ($pattern) {
return \@files;
}
@files = grep { $_ =~ $pattern } @files;
carp "Could not find any matching files" unless @files;
my %versions =
map {
if ($_ =~ $pattern and defined $1) {
( $1 => $_ )
} else {
()
}
}
@files;
if (scalar keys %versions) {
return \%versions;
} else {
return \@files;
}
}
Эта реализация пытается создать хэш и возвращает ее, если она преуспевает. Мой вопрос: могу ли я обнаружить, что qr
имеет группу захвата и только пытается создать хэш, если он делает?
Вы можете использовать что-то вроде:
sub capturing_groups{
my $re = shift;
"" =~ /|$re/;
return $#+;
}
say capturing_groups qr/fo(.)b(..)/;
Вывод:
2
use strictures;
use Carp qw(carp);
use Regexp::Parser qw();
my $parser = Regexp::Parser->new;
sub filter_files {
my ($files, $pattern) = @_;
my @files = @$files;
return \@files unless $pattern;
carp sprintf('Could not inspect regex "%s": %s (%d)',
$pattern, $parser->errmsg, $parser->errnum)
unless $parser->regex($pattern);
my %versions;
@files = map {
if (my ($capture) = $_ =~ $pattern) {
$parser->nparen
? push @{ $versions{$capture} }, $_
: $_
} else {
()
}
} @files;
carp 'Could not find any matching files' unless @files;
return (scalar keys %versions)
? \%versions
: \@files;
}
Другая возможность избежать проверки шаблона - это просто полагаться на значение $capture
. Это будет 1
(истинное значение Perl) в случае успешного совпадения без захвата. Вы можете отличить его от случайного захвата, возвращающего 1
, потому что ему не хватает флага IV
.
Вы можете использовать YAPE:: Regex для синтаксического анализа регулярного выражения, чтобы увидеть, есть ли захват:
use warnings;
use strict;
use YAPE::Regex;
filter_files(qr/foo.*/);
filter_files(qr/(foo).*/);
sub filter_files {
my ($pattern) = @_;
print "$pattern ";
if (has_capture($pattern)) {
print "yes capture\n";
}
else {
print "no capture\n";
}
}
sub has_capture {
my ($pattern) = @_;
my $cap = 0;
my $p = YAPE::Regex->new($pattern);
while ($p->next()) {
if (scalar @{ $p->{CAPTURE} }) {
$cap = 1;
last;
}
}
return $cap;
}
__END__
(?-xism:foo.*) no capture
(?-xism:(foo).*) yes capture