如何检查一个路径是否是perl中另一个路径的子路径?
How to check if a path is a subpath of an other in perl?
这个问题在其他语言中有一些答案。我是 perl 的新手,我正在这样做(比较字符串比使用文件系统函数更多):
use File::Spec;
sub has_common_prefix {
my ($path, $subpath) = @_;
$path = uc (File::Spec->canonpath($path))."\";
$subpath = uc (File::Spec->canonpath($subpath));
if ( substr($subpath, 0, length($path)) eq $path ) return 1;
return 0;
};
has_common_prefix('c:\/abCD/EFgh', 'C:\abcd\efgh/ijk.txt');
我想知道是否有更好的方法来做到这一点,还有更多"perlisch" :-)
谢谢。
好吧,我破解了这个,但我并不为此感到自豪,我希望有人想出更好的东西。我搜索了 CPAN,但很惊讶没有找到任何相关内容
我的想法是使用 File::Spec::Functions
中的 abs2rel
函数。没关系,只是它为此目的太过努力,并且 return ../..
abs2rel('/usr', '/usr/a/b')
。它还将 return 在使用路径中的卷的系统上保持第一个值不变
这只是将 abs2rel
包装在一个函数 is_within
中,该函数拒绝这两种情况,但 return 的相对路径(真值)完好无损。这意味着 is within('/usr', '/usr')
将 return .
,这是事实,但如果您认为目录不应该包含自身
,则可以针对特定情况对其进行测试
注意这不会检查路径是否指向目录,也不检查路径是否存在
use strict;
use warnings 'all';
use File::Spec::Functions qw/ abs2rel file_name_is_absolute updir /;
my @pairs = (
[qw{ /usr /usr/bin } ],
[qw{ /usr/etc /usr/bin } ],
[qw{ /var /usr/bin } ],
[qw{ /usr/bin /usr/bin } ],
);
for ( @pairs ) {
my ($path, $subpath) = @$_;
my $within = is_within($subpath, $path);
printf qq{"%s" is %swithin "%s" (%s)\n},
$subpath,
($within ? '' : 'not '),
$path,
$within // 'undef';
}
sub is_within {
my ($path, $container) = @_;
my $a2r = abs2rel($path, $container);
return if file_name_is_absolute($a2r) or index($a2r, updir) == 0;
$a2r;
}
产出
"/usr/bin" is within "/usr" (bin)
"/usr/bin" is not within "/usr/etc" (undef)
"/usr/bin" is not within "/var" (undef)
"/usr/bin" is within "/usr/bin" (.)
File::Spec 及其替代品 Path::Class 不涉及文件系统,因此它们不处理大小写差异,也不处理短格式和长格式。
use Path::Class qw( dir file );
use Win32 qw( );
sub subsumes {
my $dir = dir(Win32::GetLongPathName($_[0]));
my $file = file(Win32::GetLongPathName($_[1]));
return $dir->subsumes($file);
}
这个问题在其他语言中有一些答案。我是 perl 的新手,我正在这样做(比较字符串比使用文件系统函数更多):
use File::Spec;
sub has_common_prefix {
my ($path, $subpath) = @_;
$path = uc (File::Spec->canonpath($path))."\";
$subpath = uc (File::Spec->canonpath($subpath));
if ( substr($subpath, 0, length($path)) eq $path ) return 1;
return 0;
};
has_common_prefix('c:\/abCD/EFgh', 'C:\abcd\efgh/ijk.txt');
我想知道是否有更好的方法来做到这一点,还有更多"perlisch" :-)
谢谢。
好吧,我破解了这个,但我并不为此感到自豪,我希望有人想出更好的东西。我搜索了 CPAN,但很惊讶没有找到任何相关内容
我的想法是使用 File::Spec::Functions
中的 abs2rel
函数。没关系,只是它为此目的太过努力,并且 return ../..
abs2rel('/usr', '/usr/a/b')
。它还将 return 在使用路径中的卷的系统上保持第一个值不变
这只是将 abs2rel
包装在一个函数 is_within
中,该函数拒绝这两种情况,但 return 的相对路径(真值)完好无损。这意味着 is within('/usr', '/usr')
将 return .
,这是事实,但如果您认为目录不应该包含自身
注意这不会检查路径是否指向目录,也不检查路径是否存在
use strict;
use warnings 'all';
use File::Spec::Functions qw/ abs2rel file_name_is_absolute updir /;
my @pairs = (
[qw{ /usr /usr/bin } ],
[qw{ /usr/etc /usr/bin } ],
[qw{ /var /usr/bin } ],
[qw{ /usr/bin /usr/bin } ],
);
for ( @pairs ) {
my ($path, $subpath) = @$_;
my $within = is_within($subpath, $path);
printf qq{"%s" is %swithin "%s" (%s)\n},
$subpath,
($within ? '' : 'not '),
$path,
$within // 'undef';
}
sub is_within {
my ($path, $container) = @_;
my $a2r = abs2rel($path, $container);
return if file_name_is_absolute($a2r) or index($a2r, updir) == 0;
$a2r;
}
产出
"/usr/bin" is within "/usr" (bin)
"/usr/bin" is not within "/usr/etc" (undef)
"/usr/bin" is not within "/var" (undef)
"/usr/bin" is within "/usr/bin" (.)
File::Spec 及其替代品 Path::Class 不涉及文件系统,因此它们不处理大小写差异,也不处理短格式和长格式。
use Path::Class qw( dir file );
use Win32 qw( );
sub subsumes {
my $dir = dir(Win32::GetLongPathName($_[0]));
my $file = file(Win32::GetLongPathName($_[1]));
return $dir->subsumes($file);
}