2017-05-24 106 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