如何组合重叠路径段以获取Perl中的完整路径?

时间:2009-09-15 09:43:19

标签: perl string path

我真的不喜欢Perl,但我必须将它用于我当前的任务。

这是我的问题...我有三个字符串,构成完整目录路径的元素(窗口,但也需要在* nix上工作)。例如......

$root = "c:\\checkout\\omega";
$client = "abc\\mainline";
$build = "omega\\abc\\mainline\\host\\make";

我想将这些结合起来制作一个完整的路径,例如:

"c:\\checkout\\omega\\abc\\mainline\\host\\make" 

但$ build字符串与$root和/或$client字符串之间存在重叠。如何组合这些以获得完整路径并忽略重叠。在此示例中可能会忽略$client,但在其他情况下$build may重叠$client$root重叠。

我可以想到很多可怕的混乱方法来实现它,但我认为(也许是错误的)有一种简单,干净,甚至优雅的方式,因为Perl主要是关于文本操作。

某种字符串OR操作可能。我愚蠢地试过......

($root . $client) | $build 

但这是一个按位操作,结果是垃圾!

5 个答案:

答案 0 :(得分:4)

下面这个正则表达式更适合消除重复的路径序列。

qr{ ( 
      [\\/]  # 1. starts with a path break
      .+?    # 2. whatever
    )
    \1       # whatever was captured in the previous group 
             # it forces us to backtrack on #2 until we have duplicates
             # it will necessarily have a path break at the beginning
  }x;

只要路径中没有重复的字母,Dave Webb提供的正则表达式就可以正常工作。只需创建最后一个节点'mmake',它就会中断。

我明白了:

original c:\checkout\omega\abc\mainline\omega\abc\mainline\host\mmake
overlap m
new c:\checkout\omega\abc\mainline\omega\abc\mainline\host\make

您希望重复是目录名称,而不是字符。

还需要一个简单的替换。如果您在正则表达式中看到^.*.*$,则可能不需要。在这一点上不再需要了。

事实上所有这些都可以通过以下方式完成:

$path =~ s/([\\\/]+.+?)\1/$1/;

替换某些内容并且与之相符。

File::Spec

顺便说一句,File::Spec是以独立于平台的方式连接目录的可接受方式:

my $path = File::Spec->catfile( $root, $client, $build );
$path =~ s/([\\\/]+.+?)\1/$1/;
不过,我对File::Spec有一点小小的烦恼。我喜欢使用/作为目录。并且perl 在Windows环境中与/一起工作。只要我停留在perl的范围内,我就不必使用 escape 字符(在C语言系列中)分隔路径。 File::Spec强制反斜杠与windows平台保持一致。

然而,如果这就是你要找的东西,那可能更有理由使用它。

答案 1 :(得分:3)

你有三条路径让我感到困惑,但如果你想找到两者之间的重叠,你可以在正则表达式中使用back reference

例如:

$root = "c:\\checkout\\omega";
$build = "omega\\abc\\mainline\\host\\make";    

# Concatenate Strings
$path = "$root\\$build";
print "original ",$path,"\n";

# Look for overlap using a backreference
$path =~ /^.*(.+)\1.*$/;
print "overlap ",$1,"\n";

# Do a substitution to remove the overlap
$path =~ s/^(.*)(.+)\2(.*)$/\1\2\3/;
print "new ",$path,"\n";

这将产生以下输出:

original c:\checkout\omega\omega\abc\mainline\host\make
overlap omega\
new c:\checkout\omega\abc\mainline\host\make

答案 2 :(得分:1)

这是一种方法:

  1. 使用单引号保留反斜杠(如果反斜杠是你想要的);

  2. my $ fullpath = join“”,$ root,$ client,$ build;

  3. join是字符串之间的“粘合剂” - 在这种情况下,是空的或没有。

    以上给出:

    c:\checkout\omegaabc\mainlineomega\abc\mainline\host\make
    

    因此,如果您需要在字符串之间使用反斜杠,请使用join "\\"代替:

    c:\checkout\omega\abc\mainline\omega\abc\mainline\host\make
    

    对于双引号中的字符串,\后面的字符将被转义。在单引号中,保留文字字符串。

    然后你可以轻松地将反斜杠转换为(* nix)正斜杠,但这是另一个过程。使用Perl时,总是use strict;,当您从命令行运行它时,它将有助于指出任何潜在的故障。

答案 3 :(得分:0)

不知道你的结构是否有任何规则(例如,$ client在你的例子中似乎是多余的?)但如果有,那么你可以做这样的事情:

my $root  = 'c:\checkout\omega'; 
my $build = 'omega\abc\mainline\host\make';

# $root + $build minus first node
my $file = join '\\', $root, ( split /\\/, $build, 2 )[1];

答案 4 :(得分:0)

  

我可以想到很多可怕的混乱   实现它的方法,但我认为   (也许是错误的)有一个   简单,干净,甚至优雅   这样做的方式

YEPP。看一下Path::Class模块。从你的问题来看,你想要做的事情并不完全清楚,但Class::Path让你以跨平台的方式操纵路径。