perl:使用替换添加到路径

时间:2017-05-24 16:12:03

标签: regex perl replace

我的脚本接收文件路径,我想将一个目录附加到路径的末尾。问题是我想知道参数是否有一个尾部斜杠是不可知的。例如:

$ 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

怎么了?

2 个答案:

答案 0 :(得分: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;

这为您提供了一种独立于平台的方式来分割和连接路径元素,并且不依赖于正则表达式匹配 - 它可能有多种破坏方式(例如您找到的方式)。

答案 1 :(得分:1)

删除/g修饰符:

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

工作正常 您只想修改最后添加一个“新”,因此使用/g修饰符毫无意义。

另请注意,您可以为正则表达式使用不同的分隔符:

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

有点清楚。