2017-05-24 60 views
0

我的腳本需要一個文件路徑,並且我想將一個目錄附加到路徑的末尾。問題是我想不確定論證是否有尾隨斜線。因此,例如:perl:使用替換添加到路徑

$ perl myscript.pl /path/to/dir 
/path/to/dir/new 
$ perl myscript.pl /path/to/dir/ 
/path/to/dir/new 

我試過$path =~ s/\/?$/\/new/g,但導致雙/new如果斜線存在:

$ perl myscript.pl /path/to/dir 
/path/to/dir/new/new 
$ perl myscript.pl /path/to/dir 
/path/to/dir/new 

有什麼不對?

回答

1

刪除該/g修改:

$path =~ s/\/?$/\/new/ 

工作正常。
你只想修改最後添加一個「新」,所以修改器沒有任何意義。


另外請注意,您可以使用不同的分隔符爲你的正則表達式:

$path =~ s{ /? $}{/new}x; 

是一點點清晰。

+0

謝謝。這工作。你能解釋發生了什麼嗎? – ewok

+1

'$'不會消耗「字符串的結尾」,它只是一個斷言(它聲稱「字符串的末尾在這裏」)。所以用'/?',你的正則表達式在兩個位置匹配:首先匹配'/'後跟行尾,然後如果匹配* nothing *緊跟行尾。明白了嗎? – Dada

+0

排序,但爲什麼不會導致無限循環? – ewok

2

因爲/g是「全球性」,並會匹配其多次重複:

#!/usr/bin/env perl 
use strict; 
use warnings; 

#turn on debugging 
use re 'debug'; 

my $path = '/path/to/dir/'; 
$path =~ s/\/?$/\/new/g; 

print $path; 

第一替補,正則表達式引擎「左」標誌「行結束」後,並不需要匹配可選/。所以再次匹配。

例如爲:

Compiling REx "/?$" 
Final program: 
    1: CURLY {0,1} (5) 
    3: EXACT </> (0) 
    5: SEOL (6) 
    6: END (0) 
floating ""$ at 0..1 (checking floating) minlen 0 
Matching REx "/?$" against "/path/to/dir/" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [0..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 12)... 
    (multiline anchor test skipped) 
    try at offset... 
Intuit: Successfully guessed: match at offset 12 
    12 <path/to/dir> </>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 1 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 
Match successful! 
Matching REx "/?$" against "" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [13..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 13)... 
    (multiline anchor test skipped) 
Intuit: Successfully guessed: match at offset 13 
    13 <path/to/dir/> <>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 0 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 
Match successful! 
Matching REx "/?$" against "" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [13..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 13)... 
    (multiline anchor test skipped) 
Intuit: Successfully guessed: match at offset 13 
    13 <path/to/dir/> <>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 0 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 

這是因爲$是零寬度位置錨。如果沒有匹配,\/?也是如此。一旦模式一直消耗到尾部/並替換..然後正則表達式引擎繼續(因爲你告訴它與/g),並找到只剩$,因爲這仍然是行的末尾。這仍然是一個有效的替代。

但是,爲什麼不改用File::Spec

#!/usr/bin/env perl 
use strict; 
use warnings; 
use File::Spec; 
use Data::Dumper; 

my $path = '/path/to/dir/'; 

my @dirs = File::Spec->splitdir($path); 

print Dumper \@dirs; 

$path = File::Spec->catdir(@dirs, "new"); 
print $path; 

這爲您提供了拆分和聯接路徑元素一個獨立於平臺的方式,並且不依賴於正則表達式匹配 - 這有各種方式就可以打破(如你找到的那個)。

+0

'第一次替換後,正則表達式引擎將'結束'標記'留下',並且不需要匹配可選的/'。我沒有關注。如果它在替換後繼續匹配,爲什麼這不會導致無限循環? – ewok

+0

如果你運行上面的代碼,你會看到正則表達式在做什麼。這是因爲'$'是零寬度,因爲是空字符串('\ /?')。因此,一旦它進行了第一次替換 - 正則表達式再次嘗試,從同一起始位置開始 - 它已經'消耗'了前一次匹配的'/',但它不需要它來匹配'$'。 – Sobrique