我有
$w="/fold1/fold2/qwerty.h"
我想剪切 /qwerty.h 并得到 /fold1/fold2
我试过了
$w=~s/\/.+\.h\z//; and $w=~s/\/.+?\.h\z//;
但那些删除整个字符串。
$w=~s/\/\w+\.h\z//;
有效,但假设我有 qwe\rty.h 而不是 qwerty.h。那再也行不通了。
我有
$w="/fold1/fold2/qwerty.h"
我想剪切 /qwerty.h 并得到 /fold1/fold2
我试过了
$w=~s/\/.+\.h\z//; and $w=~s/\/.+?\.h\z//;
但那些删除整个字符串。
$w=~s/\/\w+\.h\z//;
有效,但假设我有 qwe\rty.h 而不是 qwerty.h。那再也行不通了。
使用File::Basename,标准库中的模块之一:
use File::Basename;
my $dir = dirname( $path );
通常,当您知道数据是某种类型时,请尝试将它们视为该类型。在这种情况下,您知道它是一个文件路径,因此不要将其视为一般字符串,而是将其视为文件路径。
想想你在做什么;你想在最后删除/
,所以你的模式应该基于/
,而不是“任何字符”(.
)或“单词字符”(\w
)
$w =~ s/\/[^\/]+\.h\z//;
通过避免/
使用正则表达式分隔符可以更简洁地编写:
$w =~ s,/[^/]+\.h\z,,;
也就是说,这File::Basename
是一种更清洁、更通用的便携式解决方案。
$w=~s#(.*)/[^/]+#\1#
这也有效,只需找到最后的 / ,然后用最后 / 之前的子字符串替换整个字符串
如果File::Basename
对您不起作用,那么您可以执行以下操作:
substr( $w, 0, rindex( $w, '/' ))
我经常使用它,以至于我有几个成语:
sub rpos_of {
return unless 1 + ( my $pos = rindex( $_[0], $_[1] ));
return $pos || '0E0';
}
sub before_last {
return $_[0] unless my $pos = &rpos_of;
return substr( $_[0], 0, $pos );
}
sub after_last {
return $_[0] unless my $pos = &rpos_of;
return substr( $_[0], $pos + length( $_[1] ));
}
sub break_at_last {
return $_[0] unless my $pos = &rpos_of;
return ( substr( $_[0], 0, $pos )
, substr( $_[0], $pos + length( $_[1] ))
);
}