При всем явном запросе регулярного выражения я хотел бы предложить другие подходы.
Они также анализируют только путь (в стиле URI), как и регулярные выражения, и возвращают второй каталог.
Самый простой и эффективный, просто split строка на /
my $dir = ( split /\//, $path )[2];
split
возвращает ''
первым (перед первым /
), поэтому нам нужен третий элемент. (Обратите внимание, что мы можем использовать альтернативный разделитель для шаблона разделителя, это регулярное выражение: split m{/}, $path
.)
Используйте соответствующие модули, например URI
use URI;
my $dir = ( URI->new($path)->path_segments )[2];
или Mojo :: Path
use Mojo::Path;
my $dir = Mojo::Path->new($path)->parts->[1];
Что использовать, зависит от деталей того, что вы делаете - если у вас есть какая-либо другая работа с URL-адресами и сетью, вам явно нужны модули для этого; в противном случае они могут (или не могут) быть излишним.
Я проверил их для проверки работоспособности модулей.
split
либо превосходит регулярное выражение на 10-15%
(регулярное выражение, использующее отрицательный символьный класс и класс, основанный на не жадном .+?
, встречаются одинаково), либо примерно одинаково с ними. Они быстрее, чем Mojo
примерно на 30%
, и только URI
серьезно отстают, в 5 раз от Mojo
.
Это для путей, типичных для реальных URL, с несколькими короткими компонентами. С только двумя очень длинными строками (10 тыс. Символов) Mojo::Path
(что удивительно для меня) в шесть раз опережает split
(!), Который опережает регулярное выражение класса символов более чем на порядок.
Регулярное выражение класса отрицательных символов для таких длинных строк превосходит не жадного (.+?
) в 3 раза, что полезно знать само по себе.
Во всем этом объекты URI и Mojo были созданы один раз, заранее.
Код теста. Я хотел бы отметить, что детали этих временных параметров гораздо менее важны, чем структура и качество кода.
use warnings;
use strict;
use feature 'say';
use URI;
use Mojo::Path;
use Benchmark qw(cmpthese);
my $runfor = shift // 3; #/
#my $path = '/' . 'a' x 10_000 . '/' . 'X' x 10_000;
my $path = q(/api/app/v1/method);
my $uri = URI->new($path);
my $mojo = Mojo::Path->new($path);
sub neg_cc {
my ($dir) = $path =~ m{ [^/]+ / ([^/]+) }x; return $dir; #/
}
sub non_greedy {
my ($dir) = $path =~ m{ .+? / (.+?) (?:/|$) }x; return $dir; #/
}
sub URI_path {
my $dir = ( $uri->path_segments )[2]; return $dir;
}
sub Mojo_path {
my $dir = $mojo->parts->[1]; return $dir;
}
sub just_split {
my $dir = ( split /\//, $path )[2]; return $dir;
}
cmpthese( -$runfor, {
neg_cc => sub { neg_cc($path) },
non_greedy => sub { non_greedy($path) },
just_split => sub { just_split($path) },
URI_path => sub { URI_path($path) },
Mojo_path => sub { Mojo_path($path) },
});
При выполнении (10 секунд) этой печати на ноутбуке с v5.16
Rate URI_path Mojo_path non_greedy neg_cc just_split
URI_path 146731/s -- -82% -87% -87% -89%
Mojo_path 834297/s 469% -- -24% -28% -36%
non_greedy 1098243/s 648% 32% -- -5% -16%
neg_cc 1158137/s 689% 39% 5% -- -11%
just_split 1308227/s 792% 57% 19% 13% --
Следует иметь в виду, что издержки на вызов функции очень велики для такой простой работы, и, несмотря на работу Benchmark
, эти числа, вероятно, лучше всего принять в качестве краткого руководства.