参考:perl string catenation and substitution in a single line?
给出输入:
home/////test/tmp/
并希望转变为:
/home/test/tmp/
(和其他文件路径一样的模式,需要尾随和前导斜杠,但没有双精度。例如/home/test/tmp/
通过,但/home/test/tmp
得到一个尾随斜杠等。)
使用三重正则表达式;
s,^/*,/,; #prefix
s,/*$,/,; #suffix
s,/+,/,g; #double slashes anywhere else.
给我们正确的结果:
#!/usr/bin/env perl
use strict;
use warnings;
my $str = 'home/////teledyne/tmp/';
$str =~ s,^/*,/,; #prefix
$str =~ s,/*$,/,; #suffix
$str =~ s,/+,/,g; #double slashes anywhere else.
print $str;
但如果我尝试使用交替组合这些模式,我会得到:
s,(^/*|/+|/*$),/,g
看起来应该工作......它实际上没有,我得到一个双尾斜线。
但是添加零宽度匹配,它可以正常工作:
s,(^/*|/+|\b/*$),/,g;
任何人都可以帮助我理解交替小组中发生的事情会有什么不同,并且只有将\b
留在那里可能会有问题吗?
答案 0 :(得分:2)
原因是/+
下的/g
交替与最后一个斜线匹配 - 然后由于锚的存在而继续搜索。它从最后一次替换后的位置继续,因此在最后一次斜线之后。该搜索在$
处匹配零斜杠并添加/
。
我们可以通过
看到这一点perl -wE'
$_ = "home/dir///end/";
while (m{( ^/* | /+ | /*$ )}gx) { say "Got |$1| at ", pos }
'
打印(对齐at ...
以便于阅读)
Got || at 0 Got |/| at 5 Got |///| at 11 Got |/| at 15 Got || at 15
实际替换
s{( ^/* | /+ | /*$ )}{ say "Got |$1| at ", pos; q(/) }egx
数字不同,因为它们指的是中间字符串中的位置,其中最后两个
... Got |/| at 14 Got || at 15
正在讲述。
我没有看到\b
出现问题,如问题或/*\b$
。
这是一个有趣的问题,但我想补充一点,
可以避免所有这些细节$_ = '/' . (join '/', grep { /./ } split '/', $_) . '/' for @paths;
答案 1 :(得分:0)
这是一个单一的正则表达式:
s='home/////test/tmp/'
perl -pe 's~^(?!/)|(?<!/)$|/{2,}~/~g' <<< "$s"
/home/test/tmp/
s='home/test/tmp'
perl -pe 's~^(?!/)|(?<!/)$|/{2,}~/~g' <<< "$s"
/home/test/tmp/
正则表达式分手:
^(?!/) # Line start if not followed by /
|
(?<!/)$ # Line end if not preceded by /
|
/{2,} # 2 or more /