2010-11-11 251 views
4

我需要从完整文件路径中获取文件的名称。我试着使用:从完整路径获取文件名

$out_fname =~ s/[\/\w+\/]+//;

但它“吃掉”也文件名的purts。

例如:

一个文件: /bla/bla/folder/file.part.1.file, 它返回: .part.1,file

回答

4

我与其他的答案一致,只是想解释的错误在你的格局。正则表达式很棘手,但值得好好学习。

方括号定义了一组将匹配的对象。在你的情况下,它将匹配正斜杠,字符(来自\w),+字符或正斜杠字符(这是多余的)。然后你说要匹配1个或更多的那些。有多个可匹配的字符串。它会匹配最早的起始字符,所以第一个/。然后它会尽可能地抓住。

这不是你想要的清楚。例如,如果您的某个目录名中有.,则您将停在那里。 /blah.foo/bar/x.y.z将返回.foo/bar/x.y.z

想想这个的方法是,你想匹配所有字符,包括最后的/

所有字符,然后斜线:/.*\//

但更安全,在前面加一个插入符号,以确保它从那里开始:/^.*\//

,并允许向前和反斜杠,使一个类为:/^.*[\/\\]/ (即elusive's answer)。

A 真的很好的参考是Learning Perl。大约有3个非常好的正则表达式章节。它们也适用于非Perl正则表达式用户。

+1

另一种方法是在字符串末尾处锚定,并在目录分隔符和字符串末尾匹配不是目录分隔符的所有内容(使用否定类,[^ ...]')例如'$ out_fname =〜m {[\/\\]([^ \/\\] +)$};我的$ filename_only = $ 1;' – plusplus 2010-11-11 14:26:50

-1

这个怎么样:

$out_fname =~ s/^.*[\/\\]//; 

应该删除你的文件名前的一切。

15

你可以这样做:

use File::Basename; 

my $path = "/bla/bla/folder/file.part.1.file"; 
my $filename = basename($path); 
+0

不仅如此,它会使您的脚本在其他操作系统上移植。 – justintime 2010-11-11 12:30:27

+1

这是正确的答案。 – 2010-11-11 12:50:36

+0

是的,当有内置函数时不要使用正则表达式。正则表达式很昂贵,但有时你必须付钱。 – Keng 2010-11-11 13:30:46

5

除了File :: Basename之外,还有Path::Class,对于更复杂的操作,特别是在处理目录或跨平台/文件系统操作时,它可能非常方便。在这种情况下这可能是矫枉过正,但可能值得了解。

use Path::Class; 

my $file = file("/bla/bla/folder/file.part.1.file"); 
my $filename = $file->basename; 
1

在目录分隔符上使用split是另一种选择。这与使用正则表达式(即使用文件名时,最好使用其他人已经考虑过边缘情况,可移植性,不同文件系统等的模块,因此不需要在后退和前进斜线上匹配),但作为另一种常用技术很有用你有一个重复分隔符的字符串。

my $file = "/bla/bla/folder/file.part.1.file"; 
my @parts = split /\//, $file; 
my $filename = $parts[-1]; 
+0

好主意!它最好的“分裂”......谢谢 – KingRider 2016-11-09 13:58:36

1

这是正是我会期待它在给定的替代保留。你说的是用最长的一串斜杠和单词字符替换掉。所以它抓住所有的字符,直到没有的第一个字符指定并删除它们。

它正在做你所要求的。我和其他人一起说使用File::Basename来表达你想要做的事情。

但这里是做同样的事情的最快方法:

my $fname = substr($out_fname, rindex($out_fname, '/') + 1); 

这里,说找到最后发生'/'字符串中,并给我一个开始那个位置之后的文本。我从来没有反对过正则表达式,但它是你真正想做的事情的简单表达。我已经做了这么久的东西就是这样,我写了一个last_after子:

sub last_after { 
    my ($string, $delim) = @_; 
    unless (length($string) and my $ln = length($delim)) { 
     return $string // ''; 
    } 
    my $ri = rindex($string, $delim); 
    return $ri == -1 ? $string : substr($string, $ri + $ln); 
} 
0

我还需要从一堆路径名的拉刚刚过去的领域。这对我有效:

grep -o '/\([^/]*\)$' inputfile > outputfile