我真的不喜欢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
但这是一个按位操作,结果是垃圾!
答案 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)
这是一种方法:
使用单引号保留反斜杠(如果反斜杠是你想要的);
my $ fullpath = join“”,$ root,$ client,$ build;
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
让你以跨平台的方式操纵路径。