对于所有明确要求的正则表达式,我想提出其他方法。
这些也只解析(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 和 web 相关的工作,那么你显然需要模块;否则他们可能(或可能不会)是矫枉过正。
我已经对这些进行了基准测试,以全面检查使用模块支付的费用。
split 要么胜过正则表达式 10-15%(使用否定字符类的正则表达式和基于非贪婪的 .+? 的正则表达式差不多),要么与它们大致相同。它们比Mojo 快大约30%,只有URI 严重滞后,比Mojo 落后5 倍。
这适用于真实 URL 的典型路径,其中包含一些简短的组件。只有两个非常长的字符串(10k 个字符),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) },
});
在装有 v5.16 的笔记本电脑上运行此打印件(10 秒)
评价 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%
非贪婪 1098243/s 648% 32% -- -5% -16%
neg_cc 1158137/s 689% 39% 5% -- -11%
just_split 1308227/s 792% 57% 19% 13% --
应该记住,对于这样一个简单的工作,函数调用的开销非常大,尽管Benchmark 的工作很出色,但这些数字可能最好作为粗略的指导。