1

我有

$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。那再也行不通了。

4

4 回答 4

7

使用File::Basename,标准库中的模块之一:

 use File::Basename;
 my $dir = dirname( $path );

通常,当您知道数据是某种类型时,请尝试将它们视为该类型。在这种情况下,您知道它是一个文件路径,因此不要将其视为一般字符串,而是将其视为文件路径。

于 2012-04-06T20:56:33.873 回答
1

想想你在做什么;你想在最后删除/,所以你的模式应该基于/,而不是“任何字符”(.)或“单词字符”(\w

$w =~ s/\/[^\/]+\.h\z//;

通过避免/使用正则表达式分隔符可以更简洁地编写:

$w =~ s,/[^/]+\.h\z,,;

也就是说,这File::Basename是一种更清洁、更通用的便携式解决方案。

于 2012-04-06T19:31:20.497 回答
0
$w=~s#(.*)/[^/]+#\1#

这也有效,只需找到最后的 / ,然后用最后 / 之前的子字符串替换整个字符串

于 2012-04-10T01:24:15.397 回答
0

如果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] ))
           );
}
于 2012-04-06T21:15:16.950 回答