在模式/ man /
下的代码中,连续匹配两次。因此,当我替换该模式时,只有第一个匹配项被匹配,而第二个匹配项不匹配。
据我了解的问题,第一个模式本身会一直匹配到第二个模式的开始(即人之后的空格是第一个模式的结束,也是第一个模式的开始)。因此第二个模式不匹配。连续发生此模式时如何全局匹配。
use strict;
use warnings;
#my $name =" man sky man "; #this works
my $name =" man man sky"; #this does'nt
$name =~s/ man / nam /g; #expected= 'nam nam sky'
print $name,"\n";
答案 0 :(得分:5)
正则表达式正在消耗与其匹配的字符。因此,为避免这种情况,在这种情况下,应使用先行和后方匹配。选中perlre
$name =~ s/(?<=\s)man(?=\s)/nam/g;
引用perlre
向前看:
(?=pattern) A zero-width positive lookahead assertion. For example, /\w+(?=\t)/ matches a word followed by a tab, without including the tab in $&.
向后看:
(?<=pattern) \K A zero-width positive lookbehind assertion. For example, /(?<=\t)\w+/ matches a word that follows a tab, without including the tab in $& . Works only for fixed-width lookbehind.
答案 1 :(得分:2)
我知道您想在空白字符或字符串的开头/结尾之间替换man
。
在这种情况下,您可以使用两种方法,正向查找包含对字符串边界和/或空格进行交替运算符检查,或负向查找包含在搜索词两端的非空白字符查找。
使用以下两种之一:
$name =~ s/(?<=^|\s)man(?=\z|\s)/nam/g;
$name =~ s/(?<!\S)man(?!\S)/nam/g;
从效率的角度来看,第二种方法更好,因为轮换有点“昂贵”。
后面的(?<=^|\s)
正向匹配字符串中的位置,该位置的前面是字符串(^
或(|
)空格(\s
)和{ {1}}正向超前确保在(?=$|\s)
之后紧跟空白或字符串结尾($
)。
后面的man
否定性匹配字符串中不立即带有非空白字符的位置,即,如果存在非空白字符,则不存在匹配项),并且(?<!\S)
否定前瞻断言(?!\S)
之后没有非空格。
查看有关Lookaround Assertions at perlre
的更多详细信息。