2010-11-11 183 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